This is the full developer documentation for Capgo # Welcome to Capgo Documentation > Master Capgo Cloud for instant app updates and explore our comprehensive collection of Capacitor plugins to enhance your mobile development ## 🚀 Capgo Cloud - Live Updates Made Simple [Section titled “🚀 Capgo Cloud - Live Updates Made Simple”](#-capgo-cloud---live-updates-made-simple) Instant Updates Deploy JavaScript, HTML, and CSS updates directly to users without app store delays. Fix bugs and ship features in minutes, not days. 3-Step Integration Get started with just `npx @capgo/cli@latest init [APIKEY]` and start pushing updates immediately with our simple integration. Mobile & Desktop Same live update system for Capacitor mobile apps and Electron desktop apps. One platform, all your apps. Complete Guide Learn everything from [quick setup](/docs/getting-started/quickstart/) to advanced deployment strategies in our comprehensive documentation. ## 📚 What’s in This Documentation [Section titled “📚 What’s in This Documentation”](#-whats-in-this-documentation) [Capgo Cloud Setup ](/docs/getting-started/quickstart/)Complete guides for integrating live updates, managing channels, CI/CD integration, and monitoring your deployments. [Electron Updater ](/docs/plugins/electron-updater/)Live updates for Electron desktop apps. Same powerful system, now for desktop applications. [20+ Capacitor Plugins ](/docs/plugins/)Explore our collection of production-ready plugins for biometrics, purchases, camera, storage, and more native features. [CLI & Public API ](/docs/cli/overview/)Automate your workflow with our CLI tools and integrate Capgo into your existing systems with our REST API. [Enterprise Solutions ](/enterprise/)Dedicated support, SLAs, custom features, and advanced security options for teams that need more. ## 🎯 Quick Links [Section titled “🎯 Quick Links”](#-quick-links) * **First time?** Start with the [5-minute quickstart](/docs/getting-started/quickstart/) * **Need a plugin?** Browse our [plugin collection](/docs/plugins/) or request [custom development](/consulting/) * **Having issues?** Check the [FAQ](/docs/faq/) or join our [Discord](https://discord.capgo.app) * **Enterprise needs?** Check our [enterprise solutions](/enterprise/) or [contact us](mailto:support@capgo.app) # What Happens When Capgo is Unavailable > Understanding Capgo behavior when service is down, canceled, or when you exceed plan limits # What Happens When Capgo is Unavailable [Section titled “What Happens When Capgo is Unavailable”](#what-happens-when-capgo-is-unavailable) Capgo is designed to be resilient and non-blocking. Your app continues to work even when Capgo services are temporarily unavailable. This document explains what happens in various scenarios. ## When Capgo Service is Down [Section titled “When Capgo Service is Down”](#when-capgo-service-is-down) If Capgo’s servers are temporarily unavailable or experiencing an outage: * **Your app continues to work normally** — Users can still open and use your app * **Updates are not downloaded** — The automatic update check fails silently * **No error is shown to users** — The update process gracefully fails in the background * **Existing updates remain** — Any previously downloaded updates stay on the device * **Updates resume automatically** — Once service is restored, normal update behavior resumes Capgo is designed with a “fail-safe” approach: if update services are unavailable, your app simply ignores the update and continues functioning normally. ## When You Cancel Capgo [Section titled “When You Cancel Capgo”](#when-you-cancel-capgo) After canceling your Capgo subscription: * **Existing updates remain on user devices** — Users who already downloaded updates keep those versions * **No new updates are downloaded** — The app stops checking for and downloading updates * **App functionality is unaffected** — Your app continues to work without any changes * **Historical data is retained** — Your dashboard and analytics data remains accessible for a period * **You can reactivate anytime** — Resubscribing restores full update functionality immediately The update mechanism gracefully degrades — your app becomes “static” but fully functional after cancellation. ## When You Exceed Your Plan Limits [Section titled “When You Exceed Your Plan Limits”](#when-you-exceed-your-plan-limits) If you exceed your plan’s MAU (Monthly Active Users), bandwidth, or storage limits: ### MAU Limits [Section titled “MAU Limits”](#mau-limits) * **New users may not receive updates** — The update check continues but may be throttled * **Existing users are unaffected** — Users who already have updates continue using them * **Analytics may be incomplete** — New user tracking might be paused ### Bandwidth Limits [Section titled “Bandwidth Limits”](#bandwidth-limits) * **Update downloads stop** — Users won’t receive new updates until you add credits or upgrade * **App remains functional** — Existing app version continues to work * **No error to users** — Update failures are silent and non-blocking ### Storage Limits [Section titled “Storage Limits”](#storage-limits) * **New uploads may fail** — You won’t be able to upload new app versions * **Existing versions remain available** — Previously uploaded bundles still work * **You can upgrade or add storage** — Resolving the limit restores full functionality ## Summary Table [Section titled “Summary Table”](#summary-table) | Scenario | App Works | Updates Download | Existing Updates Stay | | --------------------- | --------- | ------------------------------- | --------------------- | | Capgo Down | ✅ Yes | ❌ No | ✅ Yes | | Subscription Canceled | ✅ Yes | ❌ No | ✅ Yes | | MAU Limit Exceeded | ✅ Yes | ⚠️ May stop | ✅ Yes | | Bandwidth Limit | ✅ Yes | ❌ No | ✅ Yes | | Storage Limit | ✅ Yes | ⚠️ Downloads may be unavailable | ✅ Yes | ## Best Practices [Section titled “Best Practices”](#best-practices) 1. **Always test your app offline** — Ensure core functionality works without updates 2. **Keep a fallback plan** — Have a traditional app store update process as backup 3. **Monitor your limits** — Keep track of usage to avoid unexpected behavior 4. **Test cancellation scenarios** — Verify your app behaves correctly when updates stop ## Need Help? [Section titled “Need Help?”](#need-help) If you have questions about Capgo’s availability policies or need assistance, please [contact support](/docs/getting-help). # Introduction to Capgo Build > Build iOS and Android apps in the cloud without local setup. No local Mac required for iOS builds. Capgo Build is a cloud-based native app compilation service for Capacitor apps. It lets you build iOS and Android apps without maintaining local development environments - no Xcode, no Android Studio, no Mac hardware required on your own machine. ## What Capgo Build Does [Section titled “What Capgo Build Does”](#what-capgo-build-does) Capgo Build compiles the **native parts** of your Capacitor app in the cloud: * **iOS builds** run on dedicated Mac Mini Silicon M4 machines * **Android builds** run on the same Mac Mini Silicon M4 build fleet with Android Studio 2025 available * **Automatic code signing** handles certificates, provisioning profiles, and keystores * **Direct store submission** uploads signed apps to App Store Connect and Google Play You trigger builds with a single CLI command that works from anywhere - your local machine, GitHub Actions, GitLab CI, or any CI/CD pipeline. ## Build Machines and Toolchain [Section titled “Build Machines and Toolchain”](#build-machines-and-toolchain) Capgo Build runs native jobs on dedicated Mac Mini Silicon M4 machines: | Component | Specification | | ------------- | -------------------------------------------------------- | | Machine | Mac Mini Silicon M4 | | CPU | 10-core M4 CPU (4 performance cores, 6 efficiency cores) | | GPU | 10-core GPU | | Neural Engine | 16-core Neural Engine | | Memory | 16GB of RAM | | OS image | macOS Tahoe 26.2 | The build image supports Xcode 26.2, Android Studio 2025, and .NET 9/.NET 10 SDK workloads for native build pipelines. ## When to Use Capgo Build vs Live Updates [Section titled “When to Use Capgo Build vs Live Updates”](#when-to-use-capgo-build-vs-live-updates) Capgo offers two complementary features for updating your app. Here’s when to use each: | Scenario | Live Updates | Capgo Build | | --------------------------------------------------------- | :----------: | :---------: | | Bug fix in JavaScript/TypeScript code | ✓ | | | UI changes (HTML, CSS, images) | ✓ | | | Updating web dependencies | ✓ | | | Adding or removing a Capacitor plugin | | ✓ | | Updating a native SDK version | | ✓ | | Changing native permissions (Info.plist, AndroidManifest) | | ✓ | | Updating Capacitor version | | ✓ | | Modifying native code (Swift, Kotlin, Java) | | ✓ | | Changing app icon or splash screen | | ✓ | | First app store submission | | ✓ | Note **Live Updates** push JavaScript changes instantly without app store review. **Capgo Build** creates new native binaries when you change native code. Most teams use Live Updates daily and Capgo Build occasionally when native changes are needed. ## Why Use Capgo Build [Section titled “Why Use Capgo Build”](#why-use-capgo-build) No Local Mac Required for iOS Build and ship iOS apps without owning Mac hardware. Anyone on Windows, Linux, or any CI/CD system can trigger iOS builds and publish to TestFlight. Skip Local Environment Setup No need to install Xcode, Android Studio, or manage SDK versions. Capgo Build handles all native tooling - you just run the CLI command. Centralized Credentials Store your certificates and keystores in your CI/CD secrets once. Any team member can trigger builds without needing signing credentials on their local machine. Works With Any CI/CD A single CLI command integrates with any pipeline. GitHub Actions, GitLab CI, Jenkins - trigger builds as part of your existing workflow. Real-Time Build Logs Watch your build progress live in your terminal. Logs stream via Server-Sent Events so you can debug issues instantly as they happen. Direct Store Submission Signed apps upload directly to App Store Connect and Google Play. No manual steps between build completion and store submission. ## How It Works [Section titled “How It Works”](#how-it-works) When you run the build command: 1. **Upload** - The CLI zips only what’s needed (native platform folder + native dependencies) and uploads to secure cloud storage 2. **Build** - Your app compiles on dedicated infrastructure using Fastlane 3. **Sign** - Certificates and keystores are applied (they exist only in memory during the build) 4. **Submit** - Signed apps are uploaded directly to App Store Connect or Google Play 5. **Cleanup** - All build artifacts and credentials are automatically deleted Your source code stays on your machine. Only the platform-specific native code is uploaded. ## Security Model [Section titled “Security Model”](#security-model) Capgo Build is designed with zero credential storage: * **Runtime-only credentials** - Certificates and keystores are never stored in Capgo. They are uploaded and removed immediately after the build finishes. * **Ephemeral environments** - Each build runs in isolation and is destroyed after completion * **No log storage** - Build logs stream to your terminal only, never stored on Capgo servers * **Minimal upload** - Only the native platform you request is uploaded, not your full codebase. [See exactly what gets uploaded](/docs/cli/cloud-build/getting-started/#what-gets-built) ## Pricing [Section titled “Pricing”](#pricing) Build time is the only cost: * Build minutes are included in your Capgo plan * Extra minutes available via credit system * Builds run on Mac Mini Silicon M4 machines with the native toolchains already installed * No storage fees ## Next Steps [Section titled “Next Steps”](#next-steps) [Getting Started ](/docs/cli/cloud-build/getting-started/)Create your first build and see Capgo Build in action. [Credentials Setup ](/docs/cli/cloud-build/credentials/)Configure certificates for iOS and keystores for Android. [iOS Builds ](/docs/cli/cloud-build/ios/)Complete guide to building and submitting iOS apps. [Android Builds ](/docs/cli/cloud-build/android/)Complete guide to building and submitting Android apps. # Android Builds > Configure and build Android apps with Capgo Cloud Build Build and submit Android apps to Google Play Store using Capgo’s dedicated infrastructure. ## What you will learn [Section titled “What you will learn”](#what-you-will-learn) * You will learn how to upload your app via Capgo Native build * You will learn how to configure the credentials for Capgo Native Build ## Prerequisites [Section titled “Prerequisites”](#prerequisites) * You need to have an active Google Developer account * You need to have Android Studio installed * Your app must be able to build successfully with Android Studio Note I will use the following app for the tutorial: ## The first manual build [Section titled “The first manual build”](#the-first-manual-build) Before we can start thinking about building the app with Capgo, we should first set it up, and do a first Android build by hand. There are some advantages to doing a manual build first: * You will prepare the credentials for the later Capgo build * You will create a record on the Play Store Console ### Building the app manually with Android Studio [Section titled “Building the app manually with Android Studio”](#building-the-app-manually-with-android-studio) Before we can start building the app with Capgo, we need to build the app manually with Android Studio. 1. Open Android Studio Run `bunx cap open android` to open the Android Studio project. 2. Click on `Build` -> `Generate Signed App Bundles / APKs` ![Android Studio generate signed app bundles / APKs](/native-build-assets/android-studio-generate-signed-app-bundles-apks.webp) 3. Select `Android App Bundle` and click on `Next` ![Android Studio select Android App Bundle](/native-build-assets/android-studio-select-android-app-bundle.webp) ### Creating a Keystore [Section titled “Creating a Keystore”](#creating-a-keystore) Right now, you are missing the keystore file. This file is used to sign your app, which lets Google know that it’s you who built the app. To generate it, we will use the GUI method provided by Android Studio. There is also a way to do this with the command line, but we will not cover that in this tutorial. 1. Click on `Create new` ![Android Studio create new keystore](/native-build-assets/android-studio-create-new-keystore.webp) 2. Fill in the Key Store path ![Android Studio fill in key store path](/native-build-assets/android-studio-fill-in-key-store-path.webp) Caution This **IS TO BE SAVED** - it will be used later 3. Set the Key Store password ![Android Studio set key store password](/native-build-assets/android-studio-set-key-store-password.webp) Note I recommend using the same password for the Key Store and the Key Alias. Caution This **IS TO BE SAVED** - it will be used later 4. Fill the rest of the form 1. Keep the Key Alias as is (key0) 2. Fill the certificate details. I have filled it with fake details, but you should fill it with your own details. ![Android Studio fill rest of the form](/native-build-assets/android-studio-fill-rest-of-the-form.webp) 5. Click on `OK` ![Android Studio click on OK](/native-build-assets/android-studio-click-on-ok.webp) ### Finishing the manual build [Section titled “Finishing the manual build”](#finishing-the-manual-build) 1. Make sure all of the details for the keystore have been filled in correctly and click on `Next` ![Android Studio make sure all of the details for the keystore have been filled in correctly](/native-build-assets/android-studio-make-sure-all-of-the-details-for-the-keystore-have-been-filled-in-correctly.webp) 2. Select the `release` build variant and click on `Create` ![Android Studio select release build variant](/native-build-assets/android-studio-select-release-build-variant.webp) 3. After the build succeeds, you should see the following screen ![Android Studio after build succeed](/native-build-assets/android-studio-after-build-succeed.webp) 1. This popup indicates that the build succeeded. 2. Click on the `locate` button - this will open the file explorer and you should see the build there. 4. Make sure you can see the build in the file explorer ![Android Studio make sure you can see the build in the file explorer](/native-build-assets/android-studio-make-sure-you-can-see-the-build-in-the-file-explorer.webp) ### Creating the app on the Play Store Console [Section titled “Creating the app on the Play Store Console”](#creating-the-app-on-the-play-store-console) 1. Go to [Google Play Console](https://play.google.com/console/) 2. Select the correct developer account ![Google Play Console select correct developer account](/native-build-assets/google-play-console-select-correct-developer-account.webp) 3. Click on `Create app` ![Google Play Console create app](/native-build-assets/google-play-console-create-app.webp) 4. Choose the app name and the language ![Google Play Console choose the app name and the language](/native-build-assets/google-play-console-choose-the-app-name-and-the-language.webp) 5. Select the app category and if the app is paid or free ![Google Play Console select the app category and if the app is paid or free](/native-build-assets/google-play-console-select-the-app-category-and-if-the-app-is-paid-or-free.webp) 6. Accept the terms and conditions ![Google Play Console accept the terms and conditions](/native-build-assets/google-play-console-accept-the-terms-and-conditions.webp) Caution Make sure you read the terms and conditions before accepting them. 7. Click on `Create` ![Google Play Console click on create](/native-build-assets/google-play-console-click-on-create.webp) ### Creating the internal testing group [Section titled “Creating the internal testing group”](#creating-the-internal-testing-group) Now that you have created the app, you can create an internal testing group. Since I won’t actually publish the app for everyone on Play Store, I will need to create an internal testing group. Note Internal testing is still the fastest way to smoke-test your Play-distributed build before a real launch. If your developer account is a personal account created after November 13, 2023, internal testing does **not** replace the closed-testing requirement for production access. You will still need a closed test with at least 12 opted-in testers for 14 consecutive days before production. 1. Go to `internal testing` Click on `Test and release` -> `Testing` -> `Internal testing` ![Google Play Console internal testing](/native-build-assets/google-play-console-internal-testing.webp) 2. Click on `Testers` ![Google Play Console testers](/native-build-assets/google-play-console-testers.webp) 3. Click on `Create email list` ![Google Play Console create email list](/native-build-assets/google-play-console-create-email-list.webp) 4. Name the email list ![Google Play Console name the email list](/native-build-assets/google-play-console-name-the-email-list.webp) 5. Add the email addresses of the testers ![Google Play Console add the email addresses of the testers](/native-build-assets/google-play-console-add-the-email-addresses-of-the-testers.webp) 6. Press `Enter` and click on `Save` ![Google Play Console press enter and click on save](/native-build-assets/google-play-console-press-enter-and-click-on-save.webp) 7. Click on `Create group` ![Google Play Console create group](/native-build-assets/google-play-console-create-group.webp) 8. Make sure that the new list is selected and click on `Save` ![Google Play Console make sure that the new list is selected and click on save](/native-build-assets/google-play-console-make-sure-that-the-new-list-is-selected-and-click-on-save.webp) ### Uploading the app to the internal testing group [Section titled “Uploading the app to the internal testing group”](#uploading-the-app-to-the-internal-testing-group) Now that you have created the internal testing group, you can upload the app to the internal testing group. 1. Go to `Test and release` -> `Testing` -> `Internal testing` ![Google Play Console internal testing](/native-build-assets/google-play-console-internal-testing.webp) 2. Click on the `Releases` button ![Google Play Console releases button](/native-build-assets/google-play-console-releases-button.webp) 3. Click on `Create new release` ![Google Play Console create new release](/native-build-assets/google-play-console-create-new-release.webp) 4. Click on `Upload` ![Google Play Console upload](/native-build-assets/google-play-console-upload.webp) 5. Select the AAB file ![Google Play Console select AAB file](/native-build-assets/google-play-console-select-apk-file.webp) Caution Make sure you select the AAB file that you built manually with Android Studio. If this file doesn’t use the same keystore as the one you will use for the Capgo build, the Capgo Native Build will fail. 6. Wait for the AAB file to be uploaded 7. Click on `Next` ![Google Play Console next](/native-build-assets/google-play-console-next-step.webp) 8. Fix the errors Personally, at this stage I see this error ![Google Play Console big scary warning](/native-build-assets/google-play-console-big-scary-warning.webp) This is because I haven’t verified my phone number yet. I will do that and continue the tutorial. 9. Click on `Save and publish` This will publish the app to the internal testing group. ![Google Play Console save and publish](/native-build-assets/google-play-console-save-and-publish.webp) 10. Confirm the publication ![Google Play Console confirm publication](/native-build-assets/google-play-console-confirm-publication.webp) 11. Make sure the app is published ![Google Play Console make sure the app is published](/native-build-assets/google-play-console-make-sure-the-app-is-published.webp) 12. Get your temporary app name ![Google Play Console get your temporary app name](/native-build-assets/google-play-console-get-your-temporary-app-name.webp) ### Accept the invitation to internal testing group [Section titled “Accept the invitation to internal testing group”](#accept-the-invitation-to-internal-testing-group) Now that you have uploaded the app to the internal testing group, you can accept the invitation to the internal testing group. 1. Go to `Test and release` -> `Testing` -> `Internal testing` ![Google Play Console internal testing](/native-build-assets/google-play-console-internal-testing.webp) 2. Click on `Testers` ![Google Play Console testers](/native-build-assets/google-play-console-testers.webp) 3. Click on `Copy link` ![Google Play Console copy link](/native-build-assets/google-play-console-copy-link.webp) 4. Send the link to your phone, open it in the browser and click on `Accept` ![Google Play Console accept invitation](/native-build-assets/google-play-console-accept-invitation.webp) 5. Confirm the invitation has been accepted and click on “download it on Play Store” ![Google Play Console download it on Play Store](/native-build-assets/google-play-console-download-it-on-play-store.webp) 6. Install the app 1. If you had installed the app before using Android Studio, click on the `uninstall` button ![Google Play Console uninstall app](/native-build-assets/google-play-console-uninstall-app.webp) 2. Click on the `install` button ![Google Play Console install app](/native-build-assets/google-play-console-install-app.webp) 3. Open the app and confirm it has downloaded successfully [](/native-build-assets/screen-20260215-072439-1771136671038.mp4 "App downloaded successfully from Play Store internal testing") Caution If you do not see the app in Play Store, make sure you have selected the correct account in Play Store. ## Configuring Capgo Native Build (Android) [Section titled “Configuring Capgo Native Build (Android)”](#configuring-capgo-native-build-android) Now, you are ready to start the setup of Capgo Native Build. Congratulations 🎉! | Requirement | Flag | Description | Required | | --------------------------- | -------------------------------------- | ---------------------------------------------------------------------------------- | ---------------------- | | Keystore file | `--keystore ` | Path to your `.jks`/`.keystore` file used to sign the APK/AAB. | Yes | | Keystore alias | `--keystore-alias ` | Alias name of the key inside the keystore. | Yes | | Keystore key password | `--keystore-key-password ` | Password for the key. If key/store passwords match, you can provide only one. | Look at the note below | | Keystore store password | `--keystore-store-password ` | Password for the keystore. If key/store passwords match, you can provide only one. | Look at the note below | | Google Play service account | `--play-config ` | JSON service account file for Play Store uploads. | Yes | ```bash bunx @capgo/cli build credentials save --platform android \ --keystore ./path/to/keystore.jks \ --keystore-alias "your-alias" \ --keystore-key-password "key-password" \ --keystore-store-password "store-password" \ --play-config ./play-store-service-account.json ``` Note If key and store passwords are identical, provide only one of `--keystore-key-password` or `--keystore-store-password`. ### Keystore, keystore password, keystore key password, keystore alias [Section titled “Keystore, keystore password, keystore key password, keystore alias”](#keystore-keystore-password-keystore-key-password-keystore-alias) If you have followed the [manual build instructions](/docs/cli/cloud-build/android/#building-the-app-manually-with-android-studio), you should have the keystore already generated. If you have not followed the instructions, please follow them to generate the keystore. ### Google Play service account [Section titled “Google Play service account”](#google-play-service-account) Generating the Google Play service account is a manual and complex process. Yet, it is required to upload your app to Google Play. Please keep in mind the following things: * You **NEED** to be the [owner of the Developer Account](https://support.google.com/googleplay/android-developer/thread/238025575?hl=en\&msgid=238033420). Otherwise, you will not be able to setup the service account. * You will need to create a new Google Cloud Project (separate from your Google Play Account) Let’s begin. 1. Go to [Google Cloud Console](https://console.cloud.google.com/) 2. Click on the project selector ![Google Console Project Selector](/social-login-assets/google_cons_project_selector.png) 3. If you already have a project, select it. Otherwise, create a new project: Note The screenshots below are illustrative - use a name appropriate for your project. 1. Click on `New project` ![New Project button in Google Console](/social-login-assets/google_cons_new_project_btn.png) 2. Name your project and click `Create` ![Project naming screen showing name field and Create button](/social-login-assets/google_cons_name_projec.png) 3. Ensure that you are on the right project ![Project name showing in the selector indicating correct project selection](/social-login-assets/google_cons_right_proj.png) 4. Let’s click on the search bar and search for `service accounts` and click on it ![Google Console search bar](/social-login-assets/google_cons_search.png) ![Google Console search bar](/native-build-assets/google-console-search-bar.webp) 5. Let’s click on `Create service account` ![Create Service Account button in Google Console](/native-build-assets/google_cons_create_service_account_btn.webp) 6. Fill in the form for the service account and click on `Done` 1. I recommend setting the name to `Capgo Native Build Service Account` 2. For the Service Account ID, I recommend setting it to `capgo-native-build-service-acc` 3. As for the description, you don’t have to fill it in, but I recommend filling it with `Allows Capgo Native Build to build and submit the app to the Play Store` ![Google Console fill in the form for the service account](/native-build-assets/google-console-fill-in-the-form-for-the-service-account.webp) 7. Click on the newly created service account You should now see the newly created service account in the list. Click on it. ![Google Console newly created service account](/native-build-assets/google-console-newly-created-service-account.webp) Note Copy this email address as well, you will need it later. 8. Click on the `Keys` tab ![Keys tab in Google Console](/native-build-assets/google_cons_keys_tab.webp) 9. Click on `Add Key` and `Create new key` ![Google Console add key and create new key](/native-build-assets/google-console-add-key-and-create-new-key.webp) 10. Click on `JSON` and `Create` ![Create Key button in Google Console](/native-build-assets/google_cons_create_key_btn.webp) Caution Clicking on `Create` will create a new key and it will download the JSON file to your local machine. You need to save the JSON file in a safe place. It **WILL** be used later. 11. Download the JSON file The JSON file should have been downloaded automatically. You can click on `close` to close the window. ![Google Console download key](/native-build-assets/google-console-download-key.webp) ### Granting Play Store API access to the service account [Section titled “Granting Play Store API access to the service account”](#granting-play-store-api-access-to-the-service-account) The newly created service account does not yet have access to the Play Store API. To grant it, head to the Play Store Console. 1. Go to [Google Play Console](https://play.google.com/console/) 2. Select the correct developer account ![Google Play Console select correct developer account](/native-build-assets/google-play-console-select-correct-developer-account.webp) 3. Click on `Users and permissions` ![Google Play Console users and permissions](/native-build-assets/google-play-console-users-and-permissions.webp) 4. Click on `Invite new users` ![Google Play Console invite new users](/native-build-assets/google-play-console-invite-new-users.webp) 5. Copy the email address of the service account ![Google Play Console copy email address of the service account](/native-build-assets/google-play-console-copy-email-address-of-the-service-account.webp) 6. Go to `Account permissions` and grant the minimum required permissions: * In `App permissions`, grant access to your app. * In `Releases`, enable `Create, edit, and roll out releases`. * If your workflow uses Play App Signing, enable the related signing permission. * If you are unsure, use `Admin` only during setup, then reduce permissions afterward. ![Google Play Console grant permissions](/native-build-assets/google-play-console-grant-permissions.webp) 7. Click on `Invite user` ![Google Play Console invite user](/native-build-assets/google-play-console-invite-user.webp) 8. Confirm the invitation ![Google Play Console confirm invitation](/native-build-assets/google-play-console-confirm-invitation.webp) 9. Confirm that the user has been invited ![Google Play Console confirm that the user has been invited](/native-build-assets/google-play-console-confirm-that-the-user-has-been-invited.webp) ### Saving the credentials [Section titled “Saving the credentials”](#saving-the-credentials) You are now ready to save the credentials and run your first build. You can save the credentials using the following command: ```bash bunx @capgo/cli build credentials save --platform android \ --keystore ./path/to/keystore.jks \ --keystore-alias "your-alias" \ --keystore-key-password "key-password" \ --keystore-store-password "store-password" \ --play-config ./play-store-service-account.json ``` ### CI/CD setup (GitHub Actions) [Section titled “CI/CD setup (GitHub Actions)”](#cicd-setup-github-actions) If you already completed [Keystore, keystore password, keystore key password, keystore alias](#keystore-keystore-password-keystore-key-password-keystore-alias) and [Google Play service account](#google-play-service-account), you already have everything needed for CI/CD. This section only covers how to pass those values as GitHub Actions secrets and environment variables. #### 1) Convert credential files to single-line base64 [Section titled “1) Convert credential files to single-line base64”](#1-convert-credential-files-to-single-line-base64) ```bash # Android keystore (.jks or .keystore) base64 -i ./path/to/keystore.jks | tr -d '\n' > keystore_base64.txt # Google Play service account JSON base64 -i ./play-store-service-account.json | tr -d '\n' > play_config_base64.txt ``` Tip GitHub secrets should be single-line values. `tr -d '\n'` removes line breaks from base64 output. #### 2) Create repository secrets [Section titled “2) Create repository secrets”](#2-create-repository-secrets) In `GitHub > Repository > Settings > Secrets and variables > Actions`, add: | Secret name | Value | | ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | | `CAPGO_TOKEN` | Your Capgo API token | | `APP_ID` | Your Capgo app ID (example: `com.example.app`) | | `ANDROID_KEYSTORE_FILE` | Content of `keystore_base64.txt` | | `KEYSTORE_KEY_ALIAS` | Keystore alias from [Keystore, keystore password, keystore key password, keystore alias](#keystore-keystore-password-keystore-key-password-keystore-alias) | | `KEYSTORE_KEY_PASSWORD` | Keystore key password | | `KEYSTORE_STORE_PASSWORD` | Keystore store password | | `PLAY_CONFIG_JSON` | Content of `play_config_base64.txt` | Note If key and store passwords are the same, you can provide just one of `KEYSTORE_KEY_PASSWORD` or `KEYSTORE_STORE_PASSWORD`. #### 3) Use env vars in your GitHub Actions workflow [Section titled “3) Use env vars in your GitHub Actions workflow”](#3-use-env-vars-in-your-github-actions-workflow) .github/workflows/android-build.yml ```yaml name: Android Cloud Build on: workflow_dispatch: push: branches: [main] jobs: android-build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - uses: oven-sh/setup-bun@v2 with: bun-version: latest - name: Request Android build with Capgo run: bunx @capgo/cli@latest build ${{ secrets.APP_ID }} --platform android env: CAPGO_TOKEN: ${{ secrets.CAPGO_TOKEN }} ANDROID_KEYSTORE_FILE: ${{ secrets.ANDROID_KEYSTORE_FILE }} KEYSTORE_KEY_ALIAS: ${{ secrets.KEYSTORE_KEY_ALIAS }} KEYSTORE_KEY_PASSWORD: ${{ secrets.KEYSTORE_KEY_PASSWORD }} KEYSTORE_STORE_PASSWORD: ${{ secrets.KEYSTORE_STORE_PASSWORD }} PLAY_CONFIG_JSON: ${{ secrets.PLAY_CONFIG_JSON }} ``` Tip With this setup, CI sends credentials through environment variables only. You do not need to commit signing files or upload them as workflow artifacts. ### Running the build [Section titled “Running the build”](#running-the-build) Congratulations 🎉! You are now ready to run your first build. Run: ```bash bunx @capgo/cli build com.example.app --platform android ``` And this will start the build process 🍾🥂 # Configuration Options > Complete reference for all Cloud Build CLI flags, environment variables, and credential keys Complete reference for every Cloud Build configuration option. Use this page to find the CLI flag, environment variable, or credential key for any build setting. ## Configuration Precedence [Section titled “Configuration Precedence”](#configuration-precedence) Every build option can be set in multiple ways. When the same option is set in multiple places, higher-priority sources win: ``` flowchart LR A["🔧 CLI Flag"] -->|overrides| B["🌍 Environment Variable"] B -->|overrides| C["📁 Local Credentials"] C -->|overrides| D["🏠 Global Credentials"] style A fill:#6366f1,color:#fff,stroke:#4f46e5 style B fill:#8b5cf6,color:#fff,stroke:#7c3aed style C fill:#a78bfa,color:#fff,stroke:#8b5cf6 style D fill:#c4b5fd,color:#1e1b4b,stroke:#a78bfa ``` **Example:** If your saved credentials have `SKIP_BUILD_NUMBER_BUMP=true` but you pass `--no-skip-build-number-bump` on the CLI, the CLI flag wins and build numbers will be auto-incremented. Tip For CI/CD pipelines, environment variables are usually the most convenient. For local development, saved credentials (via `build credentials save`) avoid repeating flags every time. *** ## iOS Options [Section titled “iOS Options”](#ios-options) ### Code Signing [Section titled “Code Signing”](#code-signing) | CLI Flag | Env Variable | Credential Key | Default | Description | | ------------------------------------------------- | ------------------------------------- | ------------------------------------- | ------- | ------------------------------------------------------------------------- | | `--build-certificate-base64 ` | `BUILD_CERTIFICATE_BASE64` | `BUILD_CERTIFICATE_BASE64` | — | Base64-encoded `.p12` distribution certificate | | `--build-provision-profile-base64 ` | `BUILD_PROVISION_PROFILE_BASE64` | `BUILD_PROVISION_PROFILE_BASE64` | — | Base64-encoded `.mobileprovision` provisioning profile | | `--build-provision-profile-base64-prod ` | `BUILD_PROVISION_PROFILE_BASE64_PROD` | `BUILD_PROVISION_PROFILE_BASE64_PROD` | — | Production provisioning profile (optional, for App Store distribution) | | `--p12-password ` | `P12_PASSWORD` | `P12_PASSWORD` | — | Password for the `.p12` certificate (omit if certificate has no password) | ### App Store Connect Authentication [Section titled “App Store Connect Authentication”](#app-store-connect-authentication) | CLI Flag | Env Variable | Credential Key | Default | Description | | ---------------------------------- | --------------------------- | --------------------------- | ------- | ------------------------------------------------------------ | | `--apple-key-id ` | `APPLE_KEY_ID` | `APPLE_KEY_ID` | — | App Store Connect API Key ID | | `--apple-issuer-id ` | `APPLE_ISSUER_ID` | `APPLE_ISSUER_ID` | — | App Store Connect Issuer ID (UUID) | | `--apple-key-content ` | `APPLE_KEY_CONTENT` | `APPLE_KEY_CONTENT` | — | Base64-encoded App Store Connect API key (`.p8` file) | | `--apple-profile-name ` | `APPLE_PROFILE_NAME` | `APPLE_PROFILE_NAME` | — | Provisioning profile name as shown in Apple Developer portal | | `--app-store-connect-team-id ` | `APP_STORE_CONNECT_TEAM_ID` | `APP_STORE_CONNECT_TEAM_ID` | — | App Store Connect Team ID | Note **Alternative authentication:** You can also use Apple ID + app-specific password instead of API keys. Pass `--apple-id ` and `--apple-app-specific-password ` (env vars: `APPLE_ID`, `APPLE_APP_SPECIFIC_PASSWORD`). API keys are recommended for CI/CD. ### iOS Build Settings [Section titled “iOS Build Settings”](#ios-build-settings) | CLI Flag | Env Variable | Credential Key | Default | Description | | ----------------------- | ------------------ | ------------------ | ------- | --------------------------------------- | | `--ios-scheme ` | `CAPGO_IOS_SCHEME` | `CAPGO_IOS_SCHEME` | `App` | Xcode scheme to build | | `--ios-target ` | `CAPGO_IOS_TARGET` | `CAPGO_IOS_TARGET` | `App` | Xcode target for reading build settings | *** ## Android Options [Section titled “Android Options”](#android-options) ### Keystore Signing [Section titled “Keystore Signing”](#keystore-signing) | CLI Flag | Env Variable | Credential Key | Default | Description | | -------------------------------------- | ------------------------- | ------------------------- | ------- | --------------------------------------------------------------- | | `--android-keystore-file ` | `ANDROID_KEYSTORE_FILE` | `ANDROID_KEYSTORE_FILE` | — | Base64-encoded keystore file (`.keystore` or `.jks`) | | `--keystore-key-alias ` | `KEYSTORE_KEY_ALIAS` | `KEYSTORE_KEY_ALIAS` | `key0` | Keystore key alias | | `--keystore-key-password ` | `KEYSTORE_KEY_PASSWORD` | `KEYSTORE_KEY_PASSWORD` | — | Keystore key password (falls back to store password if not set) | | `--keystore-store-password ` | `KEYSTORE_STORE_PASSWORD` | `KEYSTORE_STORE_PASSWORD` | — | Keystore store password | ### Google Play Configuration [Section titled “Google Play Configuration”](#google-play-configuration) | CLI Flag | Env Variable | Credential Key | Default | Description | | --------------------------- | ------------------ | ------------------ | ------- | --------------------------------------------------- | | `--play-config-json ` | `PLAY_CONFIG_JSON` | `PLAY_CONFIG_JSON` | — | Base64-encoded Google Play service account JSON key | ### Android Build Settings [Section titled “Android Build Settings”](#android-build-settings) | Env Variable | Default | Description | | --------------------------- | ---------- | --------------------------------------------------------------------- | | `PLAY_STORE_TRACK` | `internal` | Google Play release track (`internal`, `alpha`, `beta`, `production`) | | `PLAY_STORE_RELEASE_STATUS` | `draft` | Release status on Google Play (`draft`, `completed`) | *** ## Build Control Options [Section titled “Build Control Options”](#build-control-options) These options work for both iOS and Android builds. ### Build Mode [Section titled “Build Mode”](#build-mode) | CLI Flag | Default | Description | | ----------------------- | --------- | ----------------------------------- | | `--platform ` | — | **Required.** `ios` or `android` | | `--build-mode ` | `release` | `debug` or `release` | | `--build-config ` | — | Additional JSON build configuration | | `--path ` | `.` | Project directory | | `--verbose` | `false` | Enable verbose build logging | ### Build Number Control [Section titled “Build Number Control”](#build-number-control) | CLI Flag | Env Variable | Credential Key | Default | Description | | ----------------------------- | ------------------------ | ------------------------ | ------- | ----------------------------------------------------------------- | | `--skip-build-number-bump` | `SKIP_BUILD_NUMBER_BUMP` | `SKIP_BUILD_NUMBER_BUMP` | `false` | Skip automatic build number / version code incrementing | | `--no-skip-build-number-bump` | — | — | — | Explicitly re-enable auto-increment (overrides saved credentials) | By default, Capgo Cloud Build automatically increments build numbers: * **iOS:** Fetches latest build number from App Store Connect, increments by 1 * **Android:** Fetches max `versionCode` from Google Play, increments by 1 When `--skip-build-number-bump` is set, the build uses whatever version is already in your project files (Xcode project or `build.gradle`). ### Output Upload [Section titled “Output Upload”](#output-upload) | CLI Flag | Env Variable | Credential Key | Default | Description | | ------------------------------- | -------------------------------- | -------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------ | | `--output-upload` | `BUILD_OUTPUT_UPLOAD_ENABLED` | `BUILD_OUTPUT_UPLOAD_ENABLED` | `false` | Upload build outputs (IPA/APK/AAB) to Capgo storage. When set via env var, use `BUILD_OUTPUT_UPLOAD_ENABLED=true`. | | `--no-output-upload` | `BUILD_OUTPUT_UPLOAD_ENABLED` | — | — | Disable output upload. When set via env var, use `BUILD_OUTPUT_UPLOAD_ENABLED=false`. | | `--output-retention ` | `BUILD_OUTPUT_RETENTION_SECONDS` | `BUILD_OUTPUT_RETENTION_SECONDS` | `1h` | How long download links remain active | **Retention format:** Use human-readable durations like `1h`, `6h`, `2d`, `7d`. Minimum is 1 hour, maximum is 7 days. When set via env var, use seconds (e.g., `3600` for 1 hour). ### Authentication [Section titled “Authentication”](#authentication) | CLI Flag | Env Variable | Default | Description | | -------------------- | ------------- | ------- | -------------------------------------------- | | `-a, --apikey ` | `CAPGO_TOKEN` | — | Capgo API key for authentication | | `--supa-host ` | — | — | Custom Supabase host (self-hosting only) | | `--supa-anon ` | — | — | Custom Supabase anon key (self-hosting only) | *** ## Environment Variable Quick Reference [Section titled “Environment Variable Quick Reference”](#environment-variable-quick-reference) Copy-paste ready for your CI/CD pipeline. All variables are optional — only set what you need. ### iOS [Section titled “iOS”](#ios) ```bash # Code signing (required for iOS builds) BUILD_CERTIFICATE_BASE64="" BUILD_PROVISION_PROFILE_BASE64="" P12_PASSWORD="" # App Store Connect (required for store submission) APPLE_KEY_ID="ABC1234567" APPLE_ISSUER_ID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" APPLE_KEY_CONTENT="" APPLE_PROFILE_NAME="My App Distribution Profile" APP_STORE_CONNECT_TEAM_ID="TEAM123456" # Optional iOS settings CAPGO_IOS_SCHEME="App" CAPGO_IOS_TARGET="App" ``` ### Android [Section titled “Android”](#android) ```bash # Keystore signing (required for Android builds) ANDROID_KEYSTORE_FILE="" KEYSTORE_KEY_ALIAS="my-key-alias" KEYSTORE_KEY_PASSWORD="" KEYSTORE_STORE_PASSWORD="" # Google Play (required for store submission) PLAY_CONFIG_JSON="" # Optional Android settings PLAY_STORE_TRACK="internal" PLAY_STORE_RELEASE_STATUS="draft" ``` ### Build Control [Section titled “Build Control”](#build-control) ```bash # Build behavior SKIP_BUILD_NUMBER_BUMP="true" # Skip auto-increment BUILD_OUTPUT_UPLOAD_ENABLED="true" # Upload IPA/APK/AAB BUILD_OUTPUT_RETENTION_SECONDS="3600" # 1 hour download link # Authentication CAPGO_TOKEN="your-api-key" ``` *** ## Credential Storage [Section titled “Credential Storage”](#credential-storage) ### Save Credentials Locally [Section titled “Save Credentials Locally”](#save-credentials-locally) Instead of passing flags or env vars every time, save credentials once: ```bash # Save iOS credentials bunx @capgo/cli build credentials save \ --platform ios \ --certificate ./dist_cert.p12 \ --provisioning-profile ./profile.mobileprovision \ --p12-password "cert-password" \ --apple-key ./AuthKey.p8 \ --apple-key-id ABC1234567 \ --apple-issuer-id xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx \ --apple-profile-name "My App Profile" \ --apple-team-id TEAM123456 # Save Android credentials bunx @capgo/cli build credentials save \ --platform android \ --keystore ./release.keystore \ --keystore-alias my-key \ --keystore-key-password "key-pass" \ --keystore-store-password "store-pass" \ --play-config ./play-service-account.json ``` ### Storage Locations [Section titled “Storage Locations”](#storage-locations) | Flag | Location | Use Case | | ----------- | ----------------------------------------- | --------------------------------------------------- | | *(default)* | `~/.capgo-credentials/credentials.json` | Global — shared across all projects on your machine | | `--local` | `.capgo-credentials.json` in project root | Per-project — overrides global when both exist | Credentials are keyed by **app ID** (e.g. `com.example.myapp`), so a single credentials file can store settings for multiple apps without conflicts. Each app’s credentials are further split by platform (`ios` / `android`). Caution Add `.capgo-credentials.json` to your `.gitignore` if using local credentials. Never commit credentials to version control. ### Manage Saved Credentials [Section titled “Manage Saved Credentials”](#manage-saved-credentials) ```bash # List saved credentials bunx @capgo/cli build credentials list # Update a specific option without re-entering everything bunx @capgo/cli build credentials update --skip-build-number-bump # Clear saved credentials bunx @capgo/cli build credentials clear --platform ios ``` *** ## Examples [Section titled “Examples”](#examples) ### GitHub Actions [Section titled “GitHub Actions”](#github-actions) ```yaml name: Build and Submit on: push: branches: [main] jobs: build-ios: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - uses: oven-sh/setup-bun@v2 - run: bun install - run: bunx cap sync ios - run: bunx @capgo/cli build request --platform ios env: CAPGO_TOKEN: ${{ secrets.CAPGO_TOKEN }} BUILD_CERTIFICATE_BASE64: ${{ secrets.IOS_CERTIFICATE }} BUILD_PROVISION_PROFILE_BASE64: ${{ secrets.IOS_PROFILE }} P12_PASSWORD: ${{ secrets.P12_PASSWORD }} APPLE_KEY_ID: ${{ secrets.APPLE_KEY_ID }} APPLE_ISSUER_ID: ${{ secrets.APPLE_ISSUER_ID }} APPLE_KEY_CONTENT: ${{ secrets.APPLE_KEY_CONTENT }} APPLE_PROFILE_NAME: ${{ secrets.APPLE_PROFILE_NAME }} APP_STORE_CONNECT_TEAM_ID: ${{ secrets.APP_STORE_CONNECT_TEAM_ID }} build-android: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - uses: oven-sh/setup-bun@v2 - run: bun install - run: bunx cap sync android - run: bunx @capgo/cli build request --platform android env: CAPGO_TOKEN: ${{ secrets.CAPGO_TOKEN }} ANDROID_KEYSTORE_FILE: ${{ secrets.ANDROID_KEYSTORE }} KEYSTORE_KEY_ALIAS: ${{ secrets.KEYSTORE_ALIAS }} KEYSTORE_KEY_PASSWORD: ${{ secrets.KEYSTORE_KEY_PASSWORD }} KEYSTORE_STORE_PASSWORD: ${{ secrets.KEYSTORE_STORE_PASSWORD }} PLAY_CONFIG_JSON: ${{ secrets.PLAY_CONFIG_JSON }} ``` ### Using CLI Flags Directly [Section titled “Using CLI Flags Directly”](#using-cli-flags-directly) ```bash # Build iOS with all options inline bunx @capgo/cli build request \ --platform ios \ --build-mode release \ --skip-build-number-bump \ --output-retention 6h \ --apikey YOUR_API_KEY # Build Android, skip version bump, no output upload bunx @capgo/cli build request \ --platform android \ --skip-build-number-bump \ --no-output-upload \ --apikey YOUR_API_KEY ``` ### Mixed Configuration [Section titled “Mixed Configuration”](#mixed-configuration) Combine saved credentials with CLI overrides: ```bash # Save base credentials once bunx @capgo/cli build credentials save --platform ios \ --certificate ./cert.p12 \ --provisioning-profile ./profile.mobileprovision \ --output-upload # Override specific options per-build bunx @capgo/cli build request --platform ios \ --skip-build-number-bump \ --output-retention 2d ``` The saved credentials provide signing details while CLI flags override build behavior for this specific run. # Managing Credentials > Save and manage build credentials locally for iOS and Android builds Manage your iOS and Android build credentials locally for convenient cloud builds. ## Overview [Section titled “Overview”](#overview) Capgo CLI allows you to save build credentials locally on your machine in the `.capgo-credentials` folder. When you run a build, these credentials are automatically used and sent securely to Capgo’s build servers. Need Help Getting Credentials? If you don’t have your certificates and credentials yet, check these comprehensive guides: **iOS:** * [How to Get iOS Certificates](/docs/cli/cloud-build/ios/#how-to-get-ios-certificates-and-provisioning-profiles) - Step-by-step guide * [iOS Certificates Guide](/docs/cli/cloud-build/ios/) - Detailed step-by-step tutorial * [Blog: Automatic iOS Builds](https://capgo.app/blog/automatic-capacitor-ios-build-github-action/) - Complete CI/CD setup **Android:** * [Creating a Keystore](/docs/cli/cloud-build/android/#creating-a-keystore) - Step-by-step guide * [Android Certificates Guide](/docs/cli/cloud-build/android/) - Detailed step-by-step tutorial * [Blog: Automatic Android Builds](https://capgo.app/blog/automatic-capacitor-android-build-github-action/) - Complete CI/CD setup Security Guarantee **Your credentials are NEVER stored permanently on Capgo servers:** * ✅ Used ONLY during the active build process * ✅ Automatically deleted after build completion * ✅ Maximum retention: 24 hours (even if build fails) * ✅ Apps are sent directly to App Store/Play Store - we store NOTHING * ✅ Transmitted securely over HTTPS ## Commands [Section titled “Commands”](#commands) ### Save Credentials [Section titled “Save Credentials”](#save-credentials) Store your build credentials locally for automatic use: ```bash npx @capgo/cli build credentials save --platform [options] ``` ### Update Credentials [Section titled “Update Credentials”](#update-credentials) Partially update existing credentials without re-providing everything: ```bash npx @capgo/cli build credentials update --platform [options] ``` The `update` command uses **additive merge** for provisioning profiles — new profiles are merged with existing ones. To replace the entire provisioning map instead, add `--overwrite-ios-provisioning-map`. Example — add an extension profile to existing credentials: ```bash npx @capgo/cli build credentials update \ --platform ios \ --ios-provisioning-profile "com.example.app.widget=./widget_profile.mobileprovision" ``` The update command accepts the same options as `save` but all are optional — only the fields you provide are updated. ### List Credentials [Section titled “List Credentials”](#list-credentials) View currently saved credentials (passwords are masked): ```bash npx @capgo/cli build credentials list # List credentials for a specific app npx @capgo/cli build credentials list --appId com.example.app ``` ### Clear Credentials [Section titled “Clear Credentials”](#clear-credentials) Remove saved credentials from your local machine: ```bash # Clear all credentials npx @capgo/cli build credentials clear # Clear credentials for a specific app + platform npx @capgo/cli build credentials clear --appId com.example.app --platform ios ``` ### Migrate Credentials [Section titled “Migrate Credentials”](#migrate-credentials) Convert legacy single-profile format to the new multi-target format: ```bash npx @capgo/cli build credentials migrate --platform ios ``` The migrate command detects old `BUILD_PROVISION_PROFILE_BASE64` credentials, converts them to `CAPGO_IOS_PROVISIONING_MAP`, and removes the legacy keys. See [Migration from Single Profile](/docs/cli/cloud-build/ios/#migration-from-single-profile) for details. ## Saving iOS Credentials [Section titled “Saving iOS Credentials”](#saving-ios-credentials) Note **Don’t have iOS certificates yet?** See the [iOS Builds guide](/docs/cli/cloud-build/ios/#how-to-get-ios-certificates-and-provisioning-profiles) for instructions on creating certificates and provisioning profiles. ### Complete Example [Section titled “Complete Example”](#complete-example) ```bash npx @capgo/cli build credentials save \ --platform ios \ --certificate ./cert.p12 \ --p12-password "YourP12Password" \ --ios-provisioning-profile "com.example.app=./profile.mobileprovision" \ --apple-key ./AuthKey_ABC1234567.p8 \ --apple-key-id "ABC1234567" \ --apple-issuer-id "00000000-0000-0000-0000-000000000000" \ --apple-team-id "TEAM123456" ``` ### iOS Options [Section titled “iOS Options”](#ios-options) | Option | Description | Required | | -------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------- | | `--certificate ` | Path to .p12 certificate file | Yes (release) | | `--p12-password ` | Password for the .p12 certificate | Yes (release) | | `--ios-provisioning-profile ` | Provisioning profile mapping (`bundleId=path`). Repeatable for multi-target apps. If only one profile and no bundleId prefix, CLI auto-infers from the profile. | Yes (release) | | `--apple-key ` | Path to App Store Connect API .p8 key | See note¹ | | `--apple-key-id ` | App Store Connect API Key ID | See note¹ | | `--apple-issuer-id ` | App Store Connect API Issuer ID (UUID) | See note¹ | | `--apple-team-id ` | App Store Connect Team ID | Yes | | `--ios-distribution ` | Distribution mode: `app_store` (default) or `ad_hoc` | No | | `--output-upload` | Enable a time-limited Capgo download link for the build artifact | No (default: `false`) | | `--output-retention ` | How long to keep build outputs (e.g. `3600s`) | No (default: `3600s`) | | `--skip-build-number-bump` | Skip automatic build-number increment | No | ¹ App Store Connect API Key Requirements * **`app_store` mode** (default): All three API key options are **required** unless you pass `--output-upload` or `--skip-build-number-bump` (which bypass the need for API-driven submission). * **`ad_hoc` mode**: These options are **not required** — no App Store submission takes place. See [Ad-Hoc Distribution Mode](/docs/cli/cloud-build/ios/#ad-hoc-distribution-mode) for details. ### What Gets Stored [Section titled “What Gets Stored”](#what-gets-stored) When you save iOS credentials, the CLI: 1. Reads the certificate and provisioning profile files 2. Converts them to base64 encoding 3. Saves the credentials to the `.capgo-credentials` folder 4. Stores passwords and IDs as plain text (local files only) The stored file structure: ```json { "ios": { "BUILD_CERTIFICATE_BASE64": "...", "CAPGO_IOS_PROVISIONING_MAP": "{\"com.example.app\":{\"profile\":\"...\",\"name\":\"match AppStore com.example.app\"}}", "APPLE_KEY_CONTENT": "...", "P12_PASSWORD": "...", "APPLE_KEY_ID": "ABC1234567", "APPLE_ISSUER_ID": "...", "APP_STORE_CONNECT_TEAM_ID": "TEAM123456", "CAPGO_IOS_DISTRIBUTION": "app_store" } } ``` ## Saving Android Credentials [Section titled “Saving Android Credentials”](#saving-android-credentials) Note **Don’t have a keystore yet?** See the [Android Builds guide](/docs/cli/cloud-build/android/#creating-a-keystore) for instructions on creating a keystore and setting up Play Store credentials. ### Complete Example [Section titled “Complete Example”](#complete-example-1) ```bash npx @capgo/cli build credentials save \ --platform android \ --keystore ./release.keystore \ --keystore-alias "my-key-alias" \ --keystore-key-password "KeyPassword123" \ --keystore-store-password "StorePassword123" \ --play-config ./play-store-service-account.json ``` ### Android Options [Section titled “Android Options”](#android-options) | Option | Description | Required | | -------------------------------------- | --------------------------------------- | ---------------- | | `--keystore ` | Path to .keystore or .jks file | Yes (release) | | `--keystore-alias ` | Key alias in the keystore | Yes (release) | | `--keystore-key-password ` | Password for the key alias | Yes (release) | | `--keystore-store-password ` | Password for the keystore | Yes (release) | | `--play-config ` | Path to Play Store service account JSON | Yes (submission) | ### What Gets Stored [Section titled “What Gets Stored”](#what-gets-stored-1) When you save Android credentials, the CLI: 1. Reads the keystore and service account JSON files 2. Converts them to base64 encoding 3. Saves the credentials to the `.capgo-credentials` folder 4. Stores passwords and alias as plain text (local files only) The stored file structure: ```json { "android": { "ANDROID_KEYSTORE_FILE": "...", "PLAY_CONFIG_JSON": "...", "KEYSTORE_KEY_ALIAS": "my-key-alias", "KEYSTORE_KEY_PASSWORD": "...", "KEYSTORE_STORE_PASSWORD": "..." } } } ``` ## Using Saved Credentials [Section titled “Using Saved Credentials”](#using-saved-credentials) Once you’ve saved credentials, they’re automatically used when you build: ```bash # Credentials automatically loaded from .capgo-credentials folder npx @capgo/cli build com.example.app --platform ios ``` You can also override saved credentials using environment variables: ```bash # Environment variables take precedence over saved credentials BUILD_CERTIFICATE_BASE64="..." \ P12_PASSWORD="different-password" \ npx @capgo/cli build com.example.app --platform ios ``` **Precedence order:** 1. Environment variables (highest priority) 2. Saved credentials in `.capgo-credentials` folder 3. No credentials (lowest priority) ## Viewing Saved Credentials [Section titled “Viewing Saved Credentials”](#viewing-saved-credentials) List what credentials you have saved: ```bash npx @capgo/cli build credentials list ``` Example output: ```plaintext 📋 Saved Build Credentials: iOS Credentials: ✓ Certificate (base64) ✓ Provisioning Map (JSON) ✓ Apple Key Content (base64) ✓ P12 Password: ******** ✓ Apple Key ID: ABC1234567 ✓ Apple Issuer ID: 00000000-0000-0000-0000-000000000000 ✓ Team ID: TEAM123456 Android Credentials: ✓ Keystore (base64) ✓ Play Store Config (base64) ✓ Keystore Alias: my-key-alias ✓ Key Password: ******** ✓ Store Password: ******** Location: .capgo-credentials/ 🔒 These credentials are stored locally on your machine only. When building, they are sent to Capgo but NEVER stored there. They are auto-deleted after build completion. ``` ## Security Best Practices [Section titled “Security Best Practices”](#security-best-practices) ### Local Storage Security [Section titled “Local Storage Security”](#local-storage-security) 1. **File Permissions** ```bash # Ensure credentials folder is not readable by others chmod 700 .capgo-credentials chmod 600 .capgo-credentials/* ``` 2. **Never Commit Credentials** ```bash # Add to .gitignore echo ".capgo-credentials/" >> .gitignore ``` 3. **Separate Credentials** * Use different credentials for local development vs CI/CD * Rotate credentials regularly * Don’t share credentials between team members ### CI/CD Usage [Section titled “CI/CD Usage”](#cicd-usage) For CI/CD environments, **prefer environment variables** over saved credentials. #### Complete Environment Variables Reference [Section titled “Complete Environment Variables Reference”](#complete-environment-variables-reference) The CLI reads the following environment variables for credentials: **iOS Credentials:** | Variable | Description | Format | Required | | ---------------------------- | ---------------------------------------------------- | --------------------------- | ------------- | | `BUILD_CERTIFICATE_BASE64` | P12/PKCS12 certificate for code signing | Base64 | Yes (release) | | `CAPGO_IOS_PROVISIONING_MAP` | JSON map of bundle IDs to provisioning profile data | JSON string | Yes (release) | | `P12_PASSWORD` | Password for the P12 certificate | Plain text | Optional | | `APPLE_KEY_ID` | App Store Connect API Key ID | String (e.g., “ABC1234567”) | See note¹ | | `APPLE_ISSUER_ID` | App Store Connect API Issuer ID | UUID string | See note¹ | | `APPLE_KEY_CONTENT` | App Store Connect API key (.p8 file content) | Base64 | See note¹ | | `APP_STORE_CONNECT_TEAM_ID` | Apple Developer Team ID | String (e.g., “XXXXXXXXXX”) | Yes | | `CAPGO_IOS_DISTRIBUTION` | Distribution mode: `app_store` (default) or `ad_hoc` | String | No | **Android Credentials:** | Variable | Description | Format | Required | | ------------------------- | --------------------------------- | ---------- | ---------------- | | `ANDROID_KEYSTORE_FILE` | Keystore file for signing APK/AAB | Base64 | Yes (release) | | `KEYSTORE_KEY_ALIAS` | Key alias within the keystore | String | Yes (release) | | `KEYSTORE_KEY_PASSWORD` | Password for the key alias | Plain text | Yes\* | | `KEYSTORE_STORE_PASSWORD` | Password for the keystore file | Plain text | Yes\* | | `PLAY_CONFIG_JSON` | Google Play service account JSON | Base64 | Yes (submission) | \*If only one password is provided, it will be used for both `KEYSTORE_KEY_PASSWORD` and `KEYSTORE_STORE_PASSWORD`. #### GitHub Actions Example [Section titled “GitHub Actions Example”](#github-actions-example) .github/workflows/build.yml ```yaml name: Cloud Build on: push: branches: [main] jobs: build-ios: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - uses: actions/setup-node@v4 with: node-version: '20' - run: npm install - run: npx @capgo/cli build com.example.app --platform ios env: CAPGO_TOKEN: ${{ secrets.CAPGO_TOKEN }} BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }} CAPGO_IOS_PROVISIONING_MAP: ${{ secrets.CAPGO_IOS_PROVISIONING_MAP }} P12_PASSWORD: ${{ secrets.P12_PASSWORD }} APPLE_KEY_ID: ${{ secrets.APPLE_KEY_ID }} APPLE_ISSUER_ID: ${{ secrets.APPLE_ISSUER_ID }} APPLE_KEY_CONTENT: ${{ secrets.APPLE_KEY_CONTENT }} APP_STORE_CONNECT_TEAM_ID: ${{ secrets.APP_STORE_CONNECT_TEAM_ID }} build-android: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - uses: actions/setup-node@v4 with: node-version: '20' - run: npm install - run: npx @capgo/cli build com.example.app --platform android env: CAPGO_TOKEN: ${{ secrets.CAPGO_TOKEN }} ANDROID_KEYSTORE_FILE: ${{ secrets.ANDROID_KEYSTORE_FILE }} KEYSTORE_KEY_ALIAS: ${{ secrets.KEYSTORE_KEY_ALIAS }} KEYSTORE_KEY_PASSWORD: ${{ secrets.KEYSTORE_KEY_PASSWORD }} KEYSTORE_STORE_PASSWORD: ${{ secrets.KEYSTORE_STORE_PASSWORD }} PLAY_CONFIG_JSON: ${{ secrets.PLAY_CONFIG_JSON }} ``` #### Preparing Base64 Values [Section titled “Preparing Base64 Values”](#preparing-base64-values) To convert your credential files to base64 for CI/CD secrets: ```bash # iOS Certificate (.p12) base64 -i certificate.p12 | tr -d '\n' > certificate_base64.txt # iOS Provisioning Profiles — use the CLI to generate CAPGO_IOS_PROVISIONING_MAP: npx @capgo/cli build credentials save --platform ios \ --ios-provisioning-profile "com.example.app=./profile.mobileprovision" \ # ... other options # Then copy CAPGO_IOS_PROVISIONING_MAP from .capgo-credentials to your CI secrets # iOS App Store Connect Key (.p8) base64 -i AuthKey_XXXXXX.p8 | tr -d '\n' > apple_key_base64.txt # Android Keystore (.keystore or .jks) base64 -i release.keystore | tr -d '\n' > keystore_base64.txt # Google Play Service Account JSON base64 -i play-store-service-account.json | tr -d '\n' > play_config_base64.txt ``` Tip The `tr -d '\n'` removes newlines to create a single-line base64 string, which is easier to store as a CI/CD secret. #### Why Environment Variables Are More Secure [Section titled “Why Environment Variables Are More Secure”](#why-environment-variables-are-more-secure) This approach is more secure because: * Secrets are managed by your CI/CD platform * No credential files on runners * Easy rotation and access control * Audit trails for secret usage ### Credential Rotation [Section titled “Credential Rotation”](#credential-rotation) Regularly rotate your credentials: 1. **iOS**: Generate new certificates and API keys yearly 2. **Android**: Change keystore passwords annually 3. **After team changes**: Rotate when team members leave Update saved credentials: ```bash # Re-run save command with new credentials npx @capgo/cli build credentials save --platform ios --certificate ./new-cert.p12 ... ``` ## Troubleshooting [Section titled “Troubleshooting”](#troubleshooting) ### ”No credentials found” [Section titled “”No credentials found””](#no-credentials-found) If the build says no credentials were found: 1. **Check if credentials are saved**: ```bash npx @capgo/cli build credentials list ``` 2. **Save credentials if missing**: ```bash npx @capgo/cli build credentials save --platform ios ... ``` 3. **Verify credentials folder exists**: ```bash ls -la .capgo-credentials/ ``` ### “Permission denied” when reading credentials [Section titled ““Permission denied” when reading credentials”](#permission-denied-when-reading-credentials) Fix file permissions: ```bash chmod 700 .capgo-credentials chmod 600 .capgo-credentials/* ``` ### Credentials not being used [Section titled “Credentials not being used”](#credentials-not-being-used) Check that the correct platform is specified: ```bash # Make sure --platform matches saved credentials npx @capgo/cli build com.example.app --platform ios # Uses ios credentials npx @capgo/cli build com.example.app --platform android # Uses android credentials ``` ### Clear and re-save credentials [Section titled “Clear and re-save credentials”](#clear-and-re-save-credentials) If credentials seem corrupted: ```bash # Clear all credentials npx @capgo/cli build credentials clear # Save again npx @capgo/cli build credentials save --platform ios ... ``` ## Migration from Environment Variables [Section titled “Migration from Environment Variables”](#migration-from-environment-variables) If you’re currently using environment variables, you can migrate to saved credentials: 1. **Extract your current environment variables** ```bash echo $BUILD_CERTIFICATE_BASE64 # Verify they exist ``` 2. **Decode base64 files back to original files** (if needed) ```bash echo "$BUILD_CERTIFICATE_BASE64" | base64 -d > cert.p12 echo "$BUILD_PROVISION_PROFILE_BASE64" | base64 -d > profile.mobileprovision ``` 3. **Save using the CLI** ```bash npx @capgo/cli build credentials save \ --platform ios \ --certificate ./cert.p12 \ --ios-provisioning-profile ./profile.mobileprovision \ --p12-password "$P12_PASSWORD" \ --apple-key-id "$APPLE_KEY_ID" \ --apple-issuer-id "$APPLE_ISSUER_ID" \ --apple-team-id "$APP_STORE_CONNECT_TEAM_ID" ``` If you have existing credentials saved in the old format (single `BUILD_PROVISION_PROFILE_BASE64`), run: ```bash npx @capgo/cli build credentials migrate --platform ios ``` This converts the legacy single-profile to a `CAPGO_IOS_PROVISIONING_MAP` and removes the old `BUILD_PROVISION_PROFILE_BASE64` and `APPLE_PROFILE_NAME` keys. 4. **Test the build** ```bash npx @capgo/cli build com.example.app --platform ios ``` 5. **Remove environment variables** (optional) ```bash unset BUILD_CERTIFICATE_BASE64 BUILD_PROVISION_PROFILE_BASE64 ``` ## File Location [Section titled “File Location”](#file-location) Credentials are stored in the `.capgo-credentials` folder: * **macOS/Linux**: `.capgo-credentials/` (in your project root or home directory) * **Windows**: `.capgo-credentials\` (in your project root or home directory) The folder is automatically created when you save credentials for the first time. ## Next Steps [Section titled “Next Steps”](#next-steps) * [Getting Started](/docs/cli/cloud-build/getting-started/) - Create your first build * [iOS Builds](/docs/cli/cloud-build/ios/) - iOS-specific build configuration * [Android Builds](/docs/cli/cloud-build/android/) - Android-specific build configuration * [Troubleshooting](/docs/cli/cloud-build/troubleshooting/) - Common issues and solutions ## Need Help? [Section titled “Need Help?”](#need-help) * 📚 [Troubleshooting guide](/docs/cli/cloud-build/troubleshooting/) * 💬 [Discord community](https://discord.com/invite/VnYRvBfgA6) * 📧 Email: # Getting Started > Create your first native build with Capgo Cloud Build Get started with Capgo Cloud Build and create your first iOS or Android native build in minutes. ## What You’ll Need [Section titled “What You’ll Need”](#what-youll-need) Before you begin, ensure you have: * A Capacitor app that builds successfully locally * Node.js 20 or higher installed * A Capgo account with an active subscription * Your app already registered in Capgo (run `bunx @capgo/cli@latest app add` if not) * **Build credentials configured** (certificates, keystores) - see below ## Before Your First Build [Section titled “Before Your First Build”](#before-your-first-build) ⚠️ Setup Credentials First **Required before building:** You must configure your build credentials (certificates for iOS, keystores for Android). [Setup Credentials →](/docs/cli/cloud-build/credentials/) ## Quick Start [Section titled “Quick Start”](#quick-start) 1. **Setup Build Credentials** Before you can build, you need to save your credentials locally: **For iOS:** ```bash bunx @capgo/cli@latest build credentials save \ --platform ios \ --certificate ./cert.p12 \ --p12-password "password" \ --provisioning-profile ./profile.mobileprovision \ --apple-key ./AuthKey.p8 \ --apple-key-id "KEY123" \ --apple-issuer-id "issuer-uuid" \ --apple-team-id "team-id" ``` **For Android:** ```bash bunx @capgo/cli@latest build credentials save \ --platform android \ --keystore ./release.keystore \ --keystore-alias "my-key" \ --keystore-key-password "key-pass" \ --keystore-store-password "store-pass" ``` See the [full credentials guide](/docs/cli/cloud-build/credentials/) for details. 2. **Verify Local Build** First, ensure your app builds locally without errors: ```bash # Build your web assets bun run build # Sync with Capacitor bunx cap sync # Test local build (optional but recommended) bunx cap open ios # For iOS bunx cap open android # For Android ``` 3. **Authenticate with Capgo** Set your Capgo API key (if not already configured): ```bash bunx @capgo/cli@latest login ``` Or set the environment variable: ```bash export CAPGO_TOKEN=your_api_key_here ``` 4. **Run Your First Build** Start with an Android debug build (fastest to test): ```bash bunx @capgo/cli@latest build com.example.app \ --platform android \ --build-mode debug ``` You’ll see real-time logs as your build progresses: ```plaintext ✔ Creating build job... ✔ Uploading project (15.2 MB)... ✔ Build started 📝 Build logs: → Installing dependencies... → Running Gradle build... → Signing APK... ✔ Build succeeded in 3m 42s ``` 5. **Check Build Status** The CLI will automatically poll and display the build status. Once complete, you’ll see: * Build time * Success/failure status * App submitted to App Store/Play Store (if credentials configured) ## Understanding the Build Process [Section titled “Understanding the Build Process”](#understanding-the-build-process) When you run the build command, here’s what happens: ``` flowchart LR A[Your Machine] -->|1. Zip Project| B[Local Temp] B -->|2. Upload| C[Capgo Cloud] C -->|3. Build| D[Mac Mini Silicon M4 Build Server] D -->|4. Logs Stream| A D -->|5. Cleanup| E[Auto Delete] ``` 1. **Local Preparation** - Your project is zipped (excluding `node_modules` and dotfiles) 2. **Upload** - The zip is uploaded to secure cloud storage (Cloudflare R2) 3. **Build Execution** - Your app builds on dedicated infrastructure 4. **Log Streaming** - Real-time logs stream to your terminal via Server-Sent Events 5. **Automatic Cleanup** - Build artifacts are deleted (Android: instant, iOS: 24 hours) ### Build Infrastructure [Section titled “Build Infrastructure”](#build-infrastructure) Build execution runs on dedicated Mac Mini Silicon M4 machines: * 10-core M4 CPU (4 performance cores, 6 efficiency cores) * 10-core GPU * 16-core Neural Engine * 16GB of RAM * macOS Tahoe 26.2 The build image supports Xcode 26.2, Android Studio 2025, and .NET 9/.NET 10 SDK workloads for native build pipelines. ## Your First Production Build [Section titled “Your First Production Build”](#your-first-production-build) Once you’ve verified the process works, create a production build: ### Android [Section titled “Android”](#android) ```bash bunx @capgo/cli@latest build com.example.app \ --platform android \ --build-mode release ``` You’ll need to configure signing credentials first. See [Android Build Configuration](/docs/cli/cloud-build/android/). ### iOS [Section titled “iOS”](#ios) ```bash bunx @capgo/cli@latest build com.example.app \ --platform ios \ --build-mode release ``` iOS builds require signing certificates and provisioning profiles. See [iOS Build Configuration](/docs/cli/cloud-build/ios/). ## What Gets Built [Section titled “What Gets Built”](#what-gets-built) Capgo Build only uploads the **minimum files needed** to compile your native app. Your full source code never leaves your machine. ### What Gets Uploaded [Section titled “What Gets Uploaded”](#what-gets-uploaded) | Included | Description | | ----------------------------------- | ---------------------------------------------------------------- | | `ios/` or `android/` | The native platform folder you’re building | | `package.json`, `package-lock.json` | Dependency manifest | | `capacitor.config.*` | Capacitor configuration | | `resources/` | App icons, splash screens | | Native plugin code | Only the `ios/` or `android/` subfolder of each Capacitor plugin | ### What’s NOT Uploaded [Section titled “What’s NOT Uploaded”](#whats-not-uploaded) | Excluded | Why | | -------------------------------------- | -------------------------------------------------------- | | `node_modules/` (most of it) | Only native plugin code is included, not JS dependencies | | `src/` | Your web source code stays local | | `dist/`, `www/`, `build/` (root level) | Already synced into the native folder via `cap sync` | | `.git/` | Version control history | | `.gradle/`, `.idea/`, `.swiftpm/` | Build caches and IDE settings | | `.env`, secrets | Never uploaded | Note Your built web assets (JS, CSS, HTML) **are** uploaded - but as part of the native folder. When you run `bunx cap sync`, your web build is copied into `ios/App/App/public/` or `android/app/src/main/assets/public/`. That’s why running `cap sync` before building is required. ### Your Responsibilities [Section titled “Your Responsibilities”](#your-responsibilities) Before running `bunx @capgo/cli@latest build`: 1. **Build your web assets** - Run `bun run build` (or your framework’s build command) 2. **Sync to native** - Run `bunx cap sync` to copy web assets into the native project 3. **Commit dependencies** - Ensure all native plugins are in `package.json` ### What Capgo Build Handles [Section titled “What Capgo Build Handles”](#what-capgo-build-handles) * Native iOS compilation (Xcode, Fastlane) * Native Android compilation (Gradle) * Code signing with your credentials * App store submission (if configured) ## Build Time & Costs [Section titled “Build Time & Costs”](#build-time--costs) Build time is measured from start to completion: * **Android**: Typically 3-5 minutes * **iOS**: Typically 5-10 minutes * **Infrastructure**: Mac Mini Silicon M4 machines running macOS Tahoe 26.2 You only pay for actual build time used. No hidden fees. ## Common Use Cases [Section titled “Common Use Cases”](#common-use-cases) ### CI/CD Integration [Section titled “CI/CD Integration”](#cicd-integration) Add to your GitHub Actions workflow: ```yaml - uses: oven-sh/setup-bun@v2 with: bun-version: latest - name: Build native app env: CAPGO_TOKEN: ${{ secrets.CAPGO_TOKEN }} run: | bun run build bunx cap sync bunx @capgo/cli@latest build ${{ secrets.APP_ID }} \ --platform both \ --build-mode release ``` ### Local Development [Section titled “Local Development”](#local-development) Test builds locally before committing: ```bash # Quick debug build for testing bun run build && bunx cap sync bunx @capgo/cli@latest build com.example.app \ --platform android \ --build-mode debug ``` ### Multi-Platform Builds [Section titled “Multi-Platform Builds”](#multi-platform-builds) Build for both platforms by running two commands: ```bash # iOS build bunx @capgo/cli@latest build com.example.app \ --platform ios \ --build-mode release # Android build bunx @capgo/cli@latest build com.example.app \ --platform android \ --build-mode release ``` In CI/CD, you can run these in parallel jobs for faster builds. ## Next Steps [Section titled “Next Steps”](#next-steps) Now that you’ve created your first build: * [Configure iOS builds](/docs/cli/cloud-build/ios/) - Set up certificates and profiles * [Configure Android builds](/docs/cli/cloud-build/android/) - Set up keystores and Play Store * [Troubleshooting](/docs/cli/cloud-build/troubleshooting/) - Common issues and solutions * [CLI Reference](/docs/cli/reference/build/) - Complete command documentation ## Need Help? [Section titled “Need Help?”](#need-help) * Check the [troubleshooting guide](/docs/cli/cloud-build/troubleshooting/) * Join our [Discord community](https://discord.com/invite/VnYRvBfgA6) * Email support at # iOS Builds > Configure and build iOS apps with Capgo Cloud Build Build and submit iOS apps to TestFlight and the App Store using Capgo’s dedicated Mac infrastructure. ## What you will learn [Section titled “What you will learn”](#what-you-will-learn) * You will learn how to upload your app via Capgo Native build * You will learn how to configure the certificates for Capgo Native Build ## Prerequisites [Section titled “Prerequisites”](#prerequisites) * A Capgo account with an active subscription * Your app already registered in Capgo (run `bunx @capgo/cli@latest app add` if not) * A Mac computer with Xcode installed (it’s possible to setup the build on a linux/windows machine, but it’s not yet documented) * Valid Apple Developer account ($99/year) (You must have admin or owner rights on the Apple Developer account) * Your app must be able to build successfully via Xcode * A Capacitor app * A configured icon for the app. Apps without an icon cannot be uploaded to the App Store. Note I will use the following app for the tutorial: ## Before you start in Apple’s portals [Section titled “Before you start in Apple’s portals”](#before-you-start-in-apples-portals) Before you set up certificates or trigger your first TestFlight upload, make sure the Apple account and team are ready: * Turn on two-factor authentication for the Apple Account used for enrollment * Choose the right membership type: * **Individual / Sole Proprietor**: your legal personal name becomes the seller name on the App Store * **Organization**: requires a legal entity, a D-U-N-S number, a public company website, a work email on the company domain, and a person with authority to bind the organization to Apple’s agreements * Use an account that can access both Apple Developer and App Store Connect for certificates, app records, API keys, and TestFlight * Lock in your final bundle ID early. Changing it later usually means redoing App Store setup * Plan these App Store Connect items before App Review: support URL, privacy policy URL, age rating, screenshots, export compliance, and App Review contact details Note Useful official references: * [Become a member of the Apple Developer Program](https://developer.apple.com/programs/enroll/) * [Submit your apps and games](https://developer.apple.com/app-store/submitting/) * [Platform version information in App Store Connect](https://developer.apple.com/help/app-store-connect/reference/app-information/platform-version-information) ![Start Apple Developer enrollment](/_docs/start-enrollment.C-l07XkV.png) ![Continue Apple enrollment on the web](/_docs/web-enrollment.Bl6dt51u.png) ![Select the correct Apple Developer entity type](/_docs/entity-type.CQ6EfCCV.png) ![App Store Connect after enrollment](/_docs/app-store-connect-home.COt6xb99.png) Caution Apple updates its minimum SDK requirement regularly. As of **April 28, 2026**, iPhone and iPad apps uploaded to App Store Connect must be built with the **iOS & iPadOS 26 SDK or later**. ## The first manual build [Section titled “The first manual build”](#the-first-manual-build) Before we can start thinking about building the app with Capgo, we should first set it up, and do a first TestFlight build by hand. There are some advantages to doing a manual build first: * You will setup the distribution certificate on your local machine * You will create the App Store record if you haven’t done it yet * You will be able to figure out any issues with the build process linked to your app code Before we can begin, you must have the distribution certificate installed on your local machine. This is quite a bit complex, but I will explain it below. ### Setting up the distribution certificate [Section titled “Setting up the distribution certificate”](#setting-up-the-distribution-certificate) 1. Open Xcode 2. Click on `Xcode` -> `Settings...` Alternatively, you can use the shortcut `Cmd + ,` ![Xcode settings](/native-build-assets/xcode-settings.webp) 3. Go to `Accounts` ![Xcode Accounts tab](/native-build-assets/xcode-apple-accounts.webp) 4. Find the Apple Account that is added to the Apple Developer Account ![Xcode selected apple account](/native-build-assets/xcode-selected-account.webp) 5. Find the team that you will use to deploy the app ![Xcode find team](/native-build-assets/xcode-find-team.webp) 6. Click on the `Manage Certificates...` button ![Xcode manage certificates](/native-build-assets/xcode-manage-certificates.webp) 7. Make sure you can see the distribution certificate in the list ![Xcode distribution certificate](/native-build-assets/xcode-deployment-certificate.webp) 8. If you do not, you need to create a new certificate Note Apple limits the number of distribution certificates you can have to 3. If you have more than 3 certificates, you need to delete one in order to create a new one. I will not cover that in the tutorial. 1. Click on the `+` button and then on `Apple Distribution` ![Xcode add certificate](/native-build-assets/xcode-add-certificate.webp) 2. The certificate will be created automatically. You can see it in the list. Look at the previous step to confirm that you see it. Now that you have the distribution certificate installed, you can begin the build process. ### Manual build to TestFlight [Section titled “Manual build to TestFlight”](#manual-build-to-testflight) 1. Open the app in Xcode Run `bunx cap open ios` to open the app in Xcode. 2. Find and click on the `archive` button In the Xcode toolbar, find and click on the `product` -> `archive` button. ![Xcode toolbar](/native-build-assets/xcode-toolbar.webp) 3. Wait for the build to complete 4. Click on the `Distribute App` button ![Xcode distribute button](/native-build-assets/xcode-distribue-app.webp) 5. Select `TestFlight Internal Only` as the distribution method and click on `Distribute` button ![Xcode TestFlight internal only distribution method](/native-build-assets/xcode-distribue-testflight-1.webp) 6. Configure the app record Fill in the following fields: 1. Name: The name of your app - visible in the App Store 2. SKU - the SKU of your app - this is used to identify your app in the App Store 3. The primary language - the primary language of your app Then, click on the `next` button ![Xcode TestFlight configure app record](/native-build-assets/xcode-configure-app-record-testflight.webp) 7. If the creation of the app record fails, try to close the window and try to archive the app again. 8. Wait for the upload to complete 9. If everything went well, you should see the following screen ![Xcode TestFlight upload complete](/native-build-assets/xcode-upload-complete-testflight.webp) 10. Click on the `Done` button You may instinctively think that all is good now and that you will be able to see your app in TestFlight now, but there are a few more things still to finish: 1. Add yourself to TestFlight 2. Complete export compliance so the build becomes testable 3. Fill in required App Store Connect metadata such as your support URL, privacy policy URL, and age rating 4. Prepare screenshots that match the devices you actually support 5. Add App Review contact details and any test credentials before the production submission Let’s start with the first one: ### Adding yourself to TestFlight [Section titled “Adding yourself to TestFlight”](#adding-yourself-to-testflight) 1. Go to the [App Store Connect](https://appstoreconnect.apple.com/) page ![App Store Connect login page](/native-build-assets/appstore-connect-login.webp) 2. Sign in with your Apple Developer account 3. Select the team that you used when you created the app record. If you are only in one developer account, can skip this step. ![App Store Connect team selection](/native-build-assets/appstore-connect-select-team.webp) 4. Click on the `Apps` button ![App Store Connect apps button](/native-build-assets/appstore-connect-apps-button.webp) 5. Find the app you created in the previous step and click on it ![App Store Connect app selection](/native-build-assets/appstore-connect-select-app.webp) 6. Click on the `TestFlight` button ![App Store Connect testflight button](/native-build-assets/appstore-connect-testflight-button.webp) 7. Click on the `Internal Testers plus` button ![App Store Connect internal testers plus button](/native-build-assets/appstore-connect-testflight-internal-testing-plus.webp) 8. Create a new group I like to name the group “internal”. You can name it whatever you want. ![App Store Connect create new group](/native-build-assets/appstore-connect-testflight-internal-create-group.webp) 9. Click on `Invite testers` button ![App Store Connect invite testers button](/native-build-assets/appstore-connect-testflight-internal-invite-testers.webp) 10. Add yourself to the group Find yourself in the list and select the checkbox next to your name. (You may need to refresh the page to see yourself) Then, click on the `Add` button. ![App Store Connect invite tester checkbox](/native-build-assets/appstore-connect-testflight-internal-invite-tester-checkbox.webp) 11. Verify that you are added to the group Now, you should see yourself in the group. ![App Store Connect verify tester](/native-build-assets/appstore-connect-testflight-internal-verify-tester.webp) Congratulations 🎉 You have added yourself to TestFlight. Now, there is just one more thing you need to do before you can configure Capgo Native Build. ### Setting up the compliance information [Section titled “Setting up the compliance information”](#setting-up-the-compliance-information) You now need to promise Apple that your app doesn’t use any non-standard (like a custom algorithm) encryption. If your app does use any non-standard encryption, I suggest reading the [Apple documentation](https://developer.apple.com/help/app-store-connect/manage-app-information/overview-of-export-compliance) on how to handle this. There are two ways to do this: 1. You can do this by hand every time you build your app. 2. You can configure your plist file to automatically set this value to `false`. Let’s start with the first one: 1. Follow all the steps from the previous section to find the TestFlight section in App Store Connect 2. Click on `Builds -> iOS` ![App Store Connect builds iOS button](/native-build-assets/appstore-connect-builds-ios-button.webp) 3. Find the build with missing compliance information and click on `Manage` ![App Store Connect manage build](/native-build-assets/appstore-connect-manage-build.webp) 4. Select the option that best describes your app For me, this is `none`, but it might be different for you. After, click save ![App Store Connect save compliance information](/native-build-assets/appstore-connect-manage-build-compliance.webp) 5. Your app should now say `ready to test` ![App Store Connect ready to test](/native-build-assets/appstore-connect-ready-to-test.webp) As for the second one, here are the steps: 1. Open the `Info.plist` file 2. Add the following key: ```xml ITSAppUsesNonExemptEncryption ``` 3. Save the file Note [Here](https://developer.apple.com/documentation/security/complying-with-encryption-export-regulations) is the official Apple documentation on how to inform Apple of your compliance with encryption export regulations. ### Installing the TestFlight app and accepting the invitation [Section titled “Installing the TestFlight app and accepting the invitation”](#installing-the-testflight-app-and-accepting-the-invitation) Now, you are **ALMOST** ready to test your app in TestFlight. Before, you need to do the following things: 1. Download the [TestFlight app](https://apps.apple.com/us/app/testflight/id899247664) from the App Store on your iOS/iPadOS device 2. Accept the invitation to test your app I will skip the details of how to install the TestFlight app on your device. If you are not sure how to install an app, Google has some great guides on how to do it. As for accepting the invitation, you will receive an email from Apple with a link to accept the invitation. 1. Open the email from Apple with the link to accept the invitation 2. Click on `View in TestFlight` button ![TestFlight email button](/native-build-assets/testflight-email-button.webp) 3. Click on the `Install` button ![TestFlight install button](/native-build-assets/testflight-install-button.webp) 4. Install the app on your device If you have installed the app previously using Xcode, you may see the following screen. Please click on the `install` button. ![TestFlight install app](/native-build-assets/testflight-install-app.webp) 5. Wait for the app to install 6. Click on the `Open` button and click it [](/native-build-assets/testflight-open-app.mp4) Congratulations 🎉 You have accepted the invitation to test your app in TestFlight. Now, you can configure Capgo Native Build to build and submit your app to TestFlight. ## Configuring Capgo Native Build [Section titled “Configuring Capgo Native Build”](#configuring-capgo-native-build) There are a few things you need to configure in Capgo Native Build to be able to build and submit your app to TestFlight. Here is a list of the things you will pass to the Capgo CLI: | Parameter | Description | | ---------------------------- | ----------------------------------------------------------------------------------------------------- | | `--platform` | The platform to build for (`ios`) | | `--apple-team-id` | Your Apple Developer Team ID (found in [Apple Developer Portal](https://developer.apple.com/account)) | | `--apple-key` | Path to your App Store Connect API Key file (`.p8` file) | | `--apple-key-id` | The Key ID of your App Store Connect API Key | | `--apple-issuer-id` | Your App Store Connect Issuer ID | | `--certificate` | Path to your distribution certificate (`.p12` file) | | `--ios-provisioning-profile` | Provisioning profile mapping (`bundleId=path` or just path for single profile) | Example command: ```bash bunx @capgo/cli@latest build credentials save \ --platform ios \ --apple-team-id YOUR_TEAM_ID \ --apple-key '/path/to/AuthKey_XXXXX.p8' \ --apple-key-id YOUR_KEY_ID \ --apple-issuer-id YOUR_ISSUER_ID \ --certificate '/path/to/certificate.p12' \ --ios-provisioning-profile '/path/to/profile.mobileprovision' ``` ### Team ID [Section titled “Team ID”](#team-id) Let’s start with the team ID. Finding it is quite easy. 1. Go to [Apple Developer Account](https://developer.apple.com/account/) and scroll down 2. Find the `Team ID` ![Team ID location in developer account](/native-build-assets/apple_dev_team_id.png) ### Apple key, Apple key ID and Apple issuer ID [Section titled “Apple key, Apple key ID and Apple issuer ID”](#apple-key-apple-key-id-and-apple-issuer-id) Now, let’s move on to the Apple key. 1. Go to [App Store Connect user and access page](https://appstoreconnect.apple.com/access/users/) Note For me the link sometimes doesn’t work. Reload the page if it doesn’t work for you. 2. Select the correct team in the dropdown 1. Click on your name in the top right corner 2. Click on the team you want to use ![Apple Developer keys team selection](/native-build-assets/apple-developer-select-team.webp) 3. Click on the `Integrations` button ![App Store Connect integrations button](/native-build-assets/appstore-connect-integrations-button.webp) 4. Find the `issuer` Caution This **IS TO BE SAVED** - you will need it later Click on the `copy` button to copy the issuer ![App Store Connect copy issuer](/native-build-assets/appstore-connect-copy-issuer.webp) 5. Click on the plus button ![App Store Connect add key button](/native-build-assets/appstore-connect-add-key-button.webp) 6. Set the name of the key and set the access to `App manager` and click on the `Generate` button ![App Store Connect add key name, set access to app manager and generate button](/native-build-assets/appstore-connect-add-key-name.webp) 7. Save the key ID Caution This **IS TO BE SAVED** - you will need it later ![App Store Connect copy key ID](/native-build-assets/appstore-connect-copy-key-id.webp) 8. Download the key Caution This **IS TO BE SAVED** - you will need it later Danger **NEVER SHARE THE KEY WITH ANYONE - USE IT ONLY IN THE CAPGO CLI** ![App Store Connect download key](/native-build-assets/appstore-connect-download-key.webp) ![App Store Connect download key warning](/native-build-assets/appstore-connect-download-key-warning.webp) Congratulations 🎉 You have created the Apple key, Apple key ID and Apple issuer ID. ### Certificate [Section titled “Certificate”](#certificate) Now, you are ready to export the certificate. As you remember, one of the first steps of this guide was setting up the distribution certificate. However, Apple in their infinite wisdom, decided that the way you export the certificate is quite different from the way you create them 🙃 Let’s get into setting it up: 1. Open Keychain Access 1. Click `Command + Space` to open the search bar 2. Search for `Keychain Access` 3. Click on the `Keychain Access` app [](/native-build-assets/open-keychain-macos.mp4) 2. Select the `login` category and click on the `My Certificates` button ![Keychain Access login category](/native-build-assets/keychain-access-login-category.webp) 3. Find your certificate in the list The certificate should be named `Apple Distribution: [Your Name/Company] (your team ID)` ![Keychain Access find certificate](/native-build-assets/keychain-access-find-certificate.webp) 4. Right-click on the certificate and select `Export` ![Keychain Access export certificate](/native-build-assets/keychain-access-export-certificate.webp) 5. Save the certificate as a `.p12` file Caution This **IS TO BE SAVED** - you will need it later 1. Make sure to select a good name for the certificate file 2. Make sure the file format is set to `Personal Information Exchange (.p12)` 3. Click on the `Save` button ![Keychain Access save certificate dialog](/native-build-assets/keychain-access-save-certificate.webp) 6. When asked for the password, you can either: * Skip the password (recommended for simplicity): Click `OK` without entering a password * Set a password: If you prefer to protect your certificate with a password, you can set one here. Password-protected `.p12` files are fully supported by the Capgo CLI - just provide the password using the `--p12-password` option when running configuration command. ![Keychain Access save certificate password dialog](/native-build-assets/keychain-access-save-certificate-password-dialog.webp) 7. When asked for the “login keychain password”, give the password you use to login to your Mac Give the password you use to login to your Mac. Then, click on the `Allow` button. ![Keychain Access save certificate login keychain password](/native-build-assets/keychain-access-save-certificate-login-keychain-password.webp) Congratulations 🎉 You have exported the certificate. ### Provisioning profile [Section titled “Provisioning profile”](#provisioning-profile) Now, you are ready to export the provisioning profile. I promise, this is the last thing you will need to get from Apple. 1. Go to [Apple Developer Profiles](https://developer.apple.com/account/resources/profiles/list) 2. Select the correct team in the dropdown 1. Click on your name in the top right corner 2. Click on the team you want to use ![Apple Developer keys team selection](/native-build-assets/apple-developer-select-team.webp) 3. Make sure you are on the correct page It should look like this, if it doesn’t click on `profiles` in the sidebar ![Apple Developer profiles page](/native-build-assets/apple-developer-profiles-page.webp) 4. Click on the `+` button ![Apple Developer add profile button](/native-build-assets/apple-developer-add-profile-button.webp) 5. Select the profile type Select `App Store Connect` and click on the `Continue` button ![Apple Developer select profile type](/native-build-assets/apple-developer-select-profile-type.webp) 6. Select the app you want to build Find your app in the dropdown and click on the `Continue` button ![Apple Developer select app](/native-build-assets/apple-developer-select-app.webp) 7. Select the correct distribution certificate Select the certificate you exported in the previous step and click on the `Continue` button ![Apple Developer select distribution certificate](/native-build-assets/apple-developer-select-deployment-certificate.webp) If you are unsure which certificate to select, come back to Keychain Access and find the certificate you exported. Then look at the expiration date. ![Apple Developer select distribution certificate expiration date](/native-build-assets/apple-developer-select-deployment-certificate-expiration-date.webp) 8. Name the profile Give the profile a name and click on the `Generate` button Tip The profile name is automatically extracted by the Capgo CLI — you don’t need to remember it. ![Apple Developer name profile](/native-build-assets/apple-developer-name-profile.webp) 9. Download the profile Click on the `Download` button to download the profile Caution This file **IS TO BE SAVED** - you will need it later ![Apple Developer download profile](/native-build-assets/apple-developer-name-provisioning-profile.webp) Congratulations 🎉 You have now got everything you need to configure Capgo Native Build. Caution Never commit the credentials you just created to your repository. Keep them safe! 🔒 ### Running the configuration command [Section titled “Running the configuration command”](#running-the-configuration-command) You have done it! You have now got everything you need to configure Capgo Native Build. The command you will need to run is: ```bash bunx @capgo/cli@latest build credentials save \ --platform ios \ --apple-team-id UVTJ336J2D \ --apple-key ./capgo-tutorial/AuthKey_66FGQZB566.p8 \ --apple-key-id 66FGQZB566 \ --apple-issuer-id 0cd4db4a-5598-45b8-9d32-75cdf127d005 \ --certificate ./capgo-tutorial/capgo-build-tutorial-certificate.p12 \ --ios-provisioning-profile ./capgo-tutorial/capgo_native_build_tutorial.mobileprovision ``` Replace placeholder values Replace the placeholder values above with your actual credentials gathered in the previous steps: * `--apple-team-id`: Your Apple Team ID * `--apple-key`: Path to your downloaded `.p8` key file * `--apple-key-id`: Your Apple Key ID * `--apple-issuer-id`: Your Apple Issuer ID * `--certificate`: Path to your exported `.p12` certificate * `--ios-provisioning-profile`: Path to your downloaded `.mobileprovision` file (bundle ID auto-inferred for single profiles) If all went well, you will see the following output: ![Capgo CLI credentials save output](/native-build-assets/credentials-save.webp) ### CI/CD setup (GitHub Actions) [Section titled “CI/CD setup (GitHub Actions)”](#cicd-setup-github-actions) If you already completed [Team ID](#team-id), [Apple key, Apple key ID and Apple issuer ID](#apple-key-apple-key-id-and-apple-issuer-id), [Certificate](#certificate), and [Provisioning profile](#provisioning-profile), you already have everything needed for CI/CD. This section only covers how to pass those values as GitHub Actions secrets and environment variables. #### 1) Convert credential files to single-line base64 [Section titled “1) Convert credential files to single-line base64”](#1-convert-credential-files-to-single-line-base64) ```bash # Distribution certificate (.p12) base64 -i ./capgo-tutorial/capgo-build-tutorial-certificate.p12 | tr -d '\n' > certificate_base64.txt # Provisioning profile (.mobileprovision) base64 -i ./capgo-tutorial/capgo_native_build_tutorial.mobileprovision | tr -d '\n' > profile_base64.txt # App Store Connect API key (.p8) base64 -i ./capgo-tutorial/AuthKey_66FGQZB566.p8 | tr -d '\n' > apple_key_base64.txt ``` Tip GitHub secrets should be single-line values. `tr -d '\n'` removes line breaks from base64 output. #### 2) Create repository secrets [Section titled “2) Create repository secrets”](#2-create-repository-secrets) In `GitHub > Repository > Settings > Secrets and variables > Actions`, add: | Secret name | Value | | ---------------------------- | --------------------------------------------------------------------------------------------------------- | | `CAPGO_TOKEN` | Your Capgo API token | | `APP_STORE_CONNECT_TEAM_ID` | Team ID from [Team ID](#team-id) | | `APPLE_KEY_ID` | Key ID from [Apple key, Apple key ID and Apple issuer ID](#apple-key-apple-key-id-and-apple-issuer-id) | | `APPLE_ISSUER_ID` | Issuer ID from [Apple key, Apple key ID and Apple issuer ID](#apple-key-apple-key-id-and-apple-issuer-id) | | `BUILD_CERTIFICATE_BASE64` | Content of `certificate_base64.txt` | | `CAPGO_IOS_PROVISIONING_MAP` | Generated by CLI — copy from `.capgo-credentials` file | | `APPLE_KEY_CONTENT` | Content of `apple_key_base64.txt` | | `P12_PASSWORD` (optional) | Your `.p12` password if set during export | #### 3) Use env vars in your GitHub Actions workflow [Section titled “3) Use env vars in your GitHub Actions workflow”](#3-use-env-vars-in-your-github-actions-workflow) .github/workflows/ios-build.yml ```yaml name: iOS Cloud Build on: workflow_dispatch: push: branches: [main] jobs: ios-build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - uses: oven-sh/setup-bun@v2 with: bun-version: latest - name: Request iOS build with Capgo run: bunx @capgo/cli@latest build request --platform ios env: CAPGO_TOKEN: ${{ secrets.CAPGO_TOKEN }} APP_STORE_CONNECT_TEAM_ID: ${{ secrets.APP_STORE_CONNECT_TEAM_ID }} APPLE_KEY_ID: ${{ secrets.APPLE_KEY_ID }} APPLE_ISSUER_ID: ${{ secrets.APPLE_ISSUER_ID }} BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }} CAPGO_IOS_PROVISIONING_MAP: ${{ secrets.CAPGO_IOS_PROVISIONING_MAP }} APPLE_KEY_CONTENT: ${{ secrets.APPLE_KEY_CONTENT }} P12_PASSWORD: ${{ secrets.P12_PASSWORD }} ``` Tip With this setup, CI sends credentials through environment variables only. You do not need to commit signing files or upload them as workflow artifacts. ### Running the build [Section titled “Running the build”](#running-the-build) Now, you are ready to run your first build. Run the following command to build your app: ```bash bunx @capgo/cli@latest build request --platform ios ``` Congratulations 🎉 At this point, you have successfully built your app and it is ready to be submitted to the App Store. ## Ad-Hoc Distribution Mode [Section titled “Ad-Hoc Distribution Mode”](#ad-hoc-distribution-mode) By default, Capgo builds iOS apps for App Store distribution (TestFlight + App Store). If you need ad-hoc builds instead (for internal testing or CI artifact collection), you can use the `--ios-distribution` flag. Note Ad-hoc distribution is **not** the same as Enterprise (In-House) distribution. Enterprise distribution requires a separate Apple Developer Enterprise account and uses different provisioning profiles. Capgo currently supports `app_store` and `ad_hoc` modes only. ### When to use ad-hoc mode [Section titled “When to use ad-hoc mode”](#when-to-use-ad-hoc-mode) * You want to distribute IPAs directly to registered devices (no TestFlight) * You don’t have or don’t want to use an App Store Connect API key * You want to collect build artifacts via `--output-upload` without submitting to the App Store ### Requirements [Section titled “Requirements”](#requirements) Ad-hoc builds have **fewer requirements** than App Store builds: | Credential | Required? | | ------------------------------------------------ | --------- | | Distribution certificate (`.p12`) | Yes | | Ad-hoc provisioning profile (`.mobileprovision`) | Yes | | Team ID (`--apple-team-id`) | Yes | | App Store Connect API key (`.p8`) | **No** | | Apple Key ID / Issuer ID | **No** | Note In `ad_hoc` mode, `--apple-key`, `--apple-key-id`, and `--apple-issuer-id` are not supported and are ignored. This is why the two App Store Connect rows above do not show ad-hoc CLI flags; these options apply to `app_store` mode only. Caution Without an App Store Connect API key, build number auto-increment uses a timestamp-based fallback. To suppress the warning, pass `--skip-build-number-bump`. ### Creating an ad-hoc provisioning profile [Section titled “Creating an ad-hoc provisioning profile”](#creating-an-ad-hoc-provisioning-profile) Follow the same steps as [Provisioning profile](#provisioning-profile), but in step 5, select **Ad Hoc** instead of **App Store**: 1. Go to [Apple Developer Profiles](https://developer.apple.com/account/resources/profiles/list) 2. Click the `+` button 3. Select **Ad Hoc** and click Continue 4. Select your app and distribution certificate 5. Select the devices you want to register 6. Name and download the profile ### Saving ad-hoc credentials [Section titled “Saving ad-hoc credentials”](#saving-ad-hoc-credentials) ```bash bunx @capgo/cli@latest build credentials save \ --platform ios \ --ios-distribution ad_hoc \ --apple-team-id YOUR_TEAM_ID \ --certificate './certificate.p12' \ --ios-provisioning-profile './adhoc_profile.mobileprovision' ``` No `--apple-key`, `--apple-key-id`, or `--apple-issuer-id` needed. ### Running an ad-hoc build [Section titled “Running an ad-hoc build”](#running-an-ad-hoc-build) ```bash bunx @capgo/cli@latest build request \ --platform ios \ --ios-distribution ad_hoc ``` To collect the IPA as a build artifact, add `--output-upload`: ```bash bunx @capgo/cli@latest build request \ --platform ios \ --ios-distribution ad_hoc \ --output-upload ``` ### CI/CD with ad-hoc builds [Section titled “CI/CD with ad-hoc builds”](#cicd-with-ad-hoc-builds) For GitHub Actions, you need fewer secrets than App Store builds: .github/workflows/ios-adhoc-build.yml ```yaml name: iOS Ad-Hoc Build on: workflow_dispatch: jobs: ios-adhoc: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - uses: oven-sh/setup-bun@v2 with: bun-version: latest - name: Request iOS ad-hoc build run: bunx @capgo/cli@latest build request --platform ios --ios-distribution ad_hoc --output-upload env: CAPGO_TOKEN: ${{ secrets.CAPGO_TOKEN }} APP_STORE_CONNECT_TEAM_ID: ${{ secrets.APP_STORE_CONNECT_TEAM_ID }} BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }} CAPGO_IOS_PROVISIONING_MAP: ${{ secrets.CAPGO_IOS_PROVISIONING_MAP_ADHOC }} CAPGO_IOS_DISTRIBUTION: ad_hoc ``` Tip Notice that `APPLE_KEY_ID`, `APPLE_ISSUER_ID`, and `APPLE_KEY_CONTENT` are not needed for ad-hoc builds. ## Apps with Extensions (Multi-Target Signing) [Section titled “Apps with Extensions (Multi-Target Signing)”](#apps-with-extensions-multi-target-signing) If your app includes extensions (share extensions, widgets, notification service extensions, etc.), each extension target needs its own provisioning profile. Capgo supports this via the repeatable `--ios-provisioning-profile` flag. ### Example: App + Share Extension [Section titled “Example: App + Share Extension”](#example-app--share-extension) ```bash bunx @capgo/cli@latest build credentials save \ --platform ios \ --apple-team-id YOUR_TEAM_ID \ --apple-key '/path/to/AuthKey_XXXXX.p8' \ --apple-key-id YOUR_KEY_ID \ --apple-issuer-id YOUR_ISSUER_ID \ --certificate '/path/to/certificate.p12' \ --ios-provisioning-profile "com.example.app=./app_profile.mobileprovision" \ --ios-provisioning-profile "com.example.app.share-extension=./share_ext_profile.mobileprovision" ``` Each `--ios-provisioning-profile` flag maps a bundle ID to its provisioning profile file. The CLI: 1. Reads each mobileprovision file 2. Auto-extracts the profile name from the embedded plist 3. Base64-encodes the file 4. Stores everything as a single `CAPGO_IOS_PROVISIONING_MAP` credential Tip You need one distribution certificate for all targets — only provisioning profiles differ per target. ### Migration from Single Profile [Section titled “Migration from Single Profile”](#migration-from-single-profile) If you previously used `BUILD_PROVISION_PROFILE_BASE64` (single profile), run: ```bash bunx @capgo/cli build credentials migrate --platform ios ``` This converts your existing single-profile credentials to the new `CAPGO_IOS_PROVISIONING_MAP` format and removes the legacy keys (`BUILD_PROVISION_PROFILE_BASE64`, `APPLE_PROFILE_NAME`). After migration, add extension profiles with the `update` command (additive merge): ```bash bunx @capgo/cli build credentials update \ --platform ios \ --ios-provisioning-profile "com.example.app.share-extension=./share_ext_profile.mobileprovision" ``` Tip Use `update` (not `save`) to add profiles to existing credentials. The `update` command merges new profiles with existing ones. Use `save` only when setting up all credentials from scratch. ## Troubleshooting [Section titled “Troubleshooting”](#troubleshooting) ### Provisioning profile doesn’t include the XYZ capability. [Section titled “Provisioning profile doesn’t include the XYZ capability.”](#provisioning-profile-doesnt-include-the-xyz-capability) Sometimes, you might see the following error: ```plaintext Provisioning profile "YOUR_PROVISIONING_PROFILE_NAME" doesn't include the XYZ capability. (in target 'App' from project 'App')" ``` This happens because you have enabled a new capability after the provisioning profile was created. The old provisioning profile does not include the new capability yet. To fix this, you need to regenerate the provisioning profile. 1. Open [Apple Developer Portal](https://developer.apple.com/account/) 2. Select the correct team in the dropdown ![Apple Developer keys team selection](/native-build-assets/apple-developer-select-team-2.webp) 3. Click on the `Profiles` button ![Apple Developer profiles button](/native-build-assets/apple-developer-profiles-button.webp) 4. Find the provisioning profile you want to regenerate ![Apple Developer find profile](/native-build-assets/pple-developer-find-profile.webp) 5. Click on the `Edit` button ![Apple Developer edit profile](/native-build-assets/apple-developer-edit-profile.webp) 6. Click on the `Save` button ![Apple Developer save profile](/native-build-assets/apple-developer-save-profile.webp) 7. Click on the `Download` button ![Apple Developer download profile](/native-build-assets/apple-developer-download-profile.webp) 8. [Re-run the Capgo Native Build setup command](/docs/cli/cloud-build/ios/#running-the-configuration-command) with the newly downloaded profile. This should fix the issue. ### Other issues [Section titled “Other issues”](#other-issues) If for whatever reason you are having issues either with Capgo Native Build, configuring the credentials or building the app, please don’t hesitate to reach via our [support](https://support.capgo.app/). # Troubleshooting > Common issues and solutions for Capgo Cloud Build Solutions to common issues when building native apps with Capgo Cloud Build. ## Build Failures [Section titled “Build Failures”](#build-failures) ### ”Upload failed” or “Connection timeout” [Section titled “”Upload failed” or “Connection timeout””](#upload-failed-or-connection-timeout) **Symptoms:** * Build fails during project upload * Timeout errors after 60 seconds **Solutions:** 1. **Check your internet connection** ```bash # Test connection to Capgo curl -I https://api.capgo.app ``` 2. **Reduce project size** * Ensure `node_modules/` is not being uploaded (should be auto-excluded) * Check for large files in your project: ```bash find . -type f -size +10M ``` 3. **Check upload URL expiration** * Upload URLs expire after 1 hour * If you get an expired URL error, re-run the build command Tip Large projects (>200MB) may hit timeout limits. Contact support for enterprise options. ### ”Build timeout after 10 minutes” [Section titled “”Build timeout after 10 minutes””](#build-timeout-after-10-minutes) **Symptoms:** * Build exceeds maximum allowed time * Status shows `timeout` **Solutions:** 1. **Optimize dependencies** * Remove unused npm packages * Use `npm prune --production` before building 2. **Check for network issues in build** * Some dependencies may download large files during build * Consider pre-caching with a lock file 3. **Review native dependencies** ```bash # iOS - check Podfile for heavy dependencies cat ios/App/Podfile # Android - check build.gradle cat android/app/build.gradle ``` 4. **Contact support** * If your app legitimately needs more time * We can adjust limits for specific use cases ## Authentication Issues [Section titled “Authentication Issues”](#authentication-issues) ### ”API key invalid” or “Unauthorized” [Section titled “”API key invalid” or “Unauthorized””](#api-key-invalid-or-unauthorized) **Symptoms:** * Build fails immediately with authentication error * 401 or 403 errors **Solutions:** 1. **Verify API key is correct** ```bash # Test with a simple command npx @capgo/cli@latest app list ``` 2. **Check API key permissions** * Key must have `write` or `all` permissions * Check in Capgo dashboard under API Keys 3. **Ensure API key is being read** ```bash # Check environment variable echo $CAPGO_TOKEN # Or verify local .capgo file cat .capgo ``` 4. **Re-authenticate** ```bash npx @capgo/cli@latest login ``` ### ”App not found” or “No permission for this app” [Section titled “”App not found” or “No permission for this app””](#app-not-found-or-no-permission-for-this-app) **Symptoms:** * Authentication works but app-specific error **Solutions:** 1. **Verify app is registered** ```bash npx @capgo/cli@latest app list ``` 2. **Check app ID matches** * Verify `capacitor.config.json` appId * Ensure command uses correct app ID 3. **Verify organization access** * Check you’re in the correct organization * API key must have access to the app’s organization ## iOS Build Issues [Section titled “iOS Build Issues”](#ios-build-issues) ### ”Code signing failed” [Section titled “”Code signing failed””](#code-signing-failed) **Symptoms:** * Build fails during code signing phase * Xcode errors about certificates or profiles **Solutions:** 1. **Verify certificate type matches build type** * Development builds need Development certificates * App Store builds need Distribution certificates 2. **Check certificate and profile match** ```bash # Decode and inspect your certificate echo $BUILD_CERTIFICATE_BASE64 | base64 -d > cert.p12 openssl pkcs12 -in cert.p12 -nokeys -passin pass:$P12_PASSWORD | openssl x509 -noout -subject ``` 3. **Ensure provisioning profile is valid** * Check expiration date * Verify it includes your App ID * Confirm it includes the certificate 4. **Regenerate credentials** * Delete old certificate/profile * Create new ones in Apple Developer portal * Re-encode and update environment variables ### ”Provisioning profile doesn’t include signing certificate” [Section titled “”Provisioning profile doesn’t include signing certificate””](#provisioning-profile-doesnt-include-signing-certificate) **Symptoms:** * Xcode can’t find certificate in profile **Solutions:** 1. **Download latest profile from Apple** * Go to Apple Developer → Certificates, IDs & Profiles * Download provisioning profile * Ensure it includes your certificate 2. **Verify certificate is in profile** ```bash # Extract profile echo $BUILD_PROVISION_PROFILE_BASE64 | base64 -d > profile.mobileprovision # View profile contents security cms -D -i profile.mobileprovision ``` 3. **Recreate profile with correct certificate** * In Apple Developer portal, edit profile * Ensure your distribution certificate is selected * Download and re-encode ### ”App Store Connect authentication failed” [Section titled “”App Store Connect authentication failed””](#app-store-connect-authentication-failed) **Symptoms:** * Upload to TestFlight fails * API key errors **Solutions:** 1. **Verify API key credentials** * Check APPLE\_KEY\_ID (should be 10 characters) * Check APPLE\_ISSUER\_ID (should be UUID format) * Verify APPLE\_KEY\_CONTENT is correctly base64-encoded 2. **Test API key locally** ```bash # Decode key echo $APPLE_KEY_CONTENT | base64 -d > AuthKey.p8 # Test with fastlane (if installed) fastlane pilot list ``` 3. **Check API key permissions** * Key needs “Developer” role or higher * Verify in App Store Connect → Users and Access → Keys 4. **Ensure key is not revoked** * Check in App Store Connect * Generate new key if needed ### ”Pod install failed” [Section titled “”Pod install failed””](#pod-install-failed) **Symptoms:** * Build fails during CocoaPods installation * Podfile errors **Solutions:** 1. **Verify Podfile.lock is committed** ```bash git status ios/App/Podfile.lock ``` 2. **Test pod install locally** ```bash cd ios/App pod install ``` 3. **Check for incompatible pods** * Review Podfile for version conflicts * Ensure all pods support your iOS deployment target 4. **Clear pod cache** ```bash cd ios/App rm -rf Pods rm Podfile.lock pod install # Then commit new Podfile.lock ``` ## Android Build Issues [Section titled “Android Build Issues”](#android-build-issues) ### ”Keystore password incorrect” [Section titled “”Keystore password incorrect””](#keystore-password-incorrect) **Symptoms:** * Build fails during signing * Gradle errors about keystore **Solutions:** 1. **Verify keystore password** ```bash # Test keystore locally keytool -list -keystore my-release-key.keystore # Enter password when prompted ``` 2. **Check environment variables** ```bash # Ensure no extra spaces or special characters echo "$KEYSTORE_STORE_PASSWORD" | cat -A echo "$KEYSTORE_KEY_PASSWORD" | cat -A ``` 3. **Verify base64 encoding** ```bash # Decode and test echo $ANDROID_KEYSTORE_FILE | base64 -d > test.keystore keytool -list -keystore test.keystore ``` ### ”Key alias not found” [Section titled “”Key alias not found””](#key-alias-not-found) **Symptoms:** * Signing fails with alias error **Solutions:** 1. **List keystore aliases** ```bash keytool -list -keystore my-release-key.keystore ``` 2. **Verify alias matches exactly** * Alias is case-sensitive * Check for typos in KEYSTORE\_KEY\_ALIAS 3. **Use correct alias from keystore** ```bash # Update environment variable to match export KEYSTORE_KEY_ALIAS="the-exact-alias-name" ``` ### ”Gradle build failed” [Section titled “”Gradle build failed””](#gradle-build-failed) **Symptoms:** * Generic Gradle errors * Compilation or dependency issues **Solutions:** 1. **Test build locally first** ```bash cd android ./gradlew clean ./gradlew assembleRelease ``` 2. **Check for missing dependencies** * Review build.gradle files * Ensure all plugins are listed in dependencies 3. **Verify Gradle version compatibility** ```bash # Check gradle version cat android/gradle/wrapper/gradle-wrapper.properties ``` 4. **Clear Gradle cache** ```bash cd android ./gradlew clean rm -rf .gradle build ``` ### ”Play Store upload failed” [Section titled “”Play Store upload failed””](#play-store-upload-failed) **Symptoms:** * Build succeeds but upload fails * Service account errors **Solutions:** 1. **Verify service account JSON** ```bash # Decode and check format echo $PLAY_CONFIG_JSON | base64 -d | jq . ``` 2. **Check service account permissions** * Go to Play Console → Setup → API Access * Ensure service account has access to your app * Grant “Release to testing tracks” permission 3. **Verify app is set up in Play Console** * App must be created in Play Console first * At least one APK must be uploaded manually initially 4. **Check API is enabled** * Google Play Developer API must be enabled * Check in Google Cloud Console ## General Issues [Section titled “General Issues”](#general-issues) ### ”Job not found” or “Build status unavailable” [Section titled “”Job not found” or “Build status unavailable””](#job-not-found-or-build-status-unavailable) **Symptoms:** * Cannot check build status * Job ID errors **Solutions:** 1. **Wait a moment and retry** * Build jobs may take a few seconds to initialize 2. **Check job ID is correct** * Verify the job ID from the initial build response 3. **Check build hasn’t expired** * Build data is available for 24 hours ### ”Project sync failed” [Section titled “”Project sync failed””](#project-sync-failed) **Symptoms:** * Build fails before compilation starts * Missing files errors **Solutions:** 1. **Run Capacitor sync locally** ```bash npx cap sync ``` 2. **Ensure all native files are committed** ```bash git status ios/ android/ ``` 3. **Check for gitignored native files** * Review .gitignore * Ensure important config files aren’t ignored ### ”Build succeeded but I don’t see output” [Section titled “”Build succeeded but I don’t see output””](#build-succeeded-but-i-dont-see-output) **Symptoms:** * Build shows success but no download link **Solutions:** 1. **Check build configuration** * Artifact storage may not be configured * Contact support if artifact access is unavailable for your build 2. **For iOS TestFlight submission** * Check App Store Connect * Processing may take 5-30 minutes after upload 3. **For Android Play Store** * Check Play Console → Testing → Internal testing * Processing may take a few minutes ## CI/CD Specific Issues [Section titled “CI/CD Specific Issues”](#cicd-specific-issues) ### GitHub Actions: “Command not found” [Section titled “GitHub Actions: “Command not found””](#github-actions-command-not-found) **Symptoms:** * `npx @capgo/cli` fails in CI **Solutions:** 1. **Ensure Node.js is installed** ```yaml - uses: actions/setup-node@v6 with: node-version: '24' ``` 2. **Install CLI explicitly** ```yaml - run: npm install -g @capgo/cli ``` ### GitHub Actions: “Secrets not found” [Section titled “GitHub Actions: “Secrets not found””](#github-actions-secrets-not-found) **Symptoms:** * Environment variables empty in build **Solutions:** 1. **Verify secrets are set** * Go to repo Settings → Secrets and variables → Actions * Add all required secrets 2. **Use correct syntax** ```yaml env: CAPGO_TOKEN: ${{ secrets.CAPGO_TOKEN }} ``` 3. **Check secret names match** * Names are case-sensitive * No typos in secret references ## Getting More Help [Section titled “Getting More Help”](#getting-more-help) ### Enable Verbose Logging [Section titled “Enable Verbose Logging”](#enable-verbose-logging) ```bash # Add debug flag (when available) npx @capgo/cli@latest build com.example.app --verbose ``` ### Collect Build Information [Section titled “Collect Build Information”](#collect-build-information) When contacting support, include: 1. **Build command used** ```bash npx @capgo/cli@latest build com.example.app --platform ios ``` 2. **Error message** (full output) 3. **Job ID** (from build output) 4. **Build logs** (copy full terminal output) 5. **Environment info** ```bash node --version npm --version npx @capgo/cli --version ``` ### Contact Support [Section titled “Contact Support”](#contact-support) * **Discord**: [Join our community](https://discord.com/invite/VnYRvBfgA6) * **Email**: * **Documentation**: [Capgo Docs](/docs/) ### Known Limitations [Section titled “Known Limitations”](#known-limitations) Current limitations: * Maximum build time: 10 minutes * Maximum upload size: \~500MB * iOS builds require 24-hour Mac leases, build on Mac will enqueue to ensure optimal usage * Build artifact download availability depends on build destination and artifact storage configuration These limitations may be adjusted based on feedback. ## Additional Resources [Section titled “Additional Resources”](#additional-resources) * [Getting Started](/docs/cli/cloud-build/getting-started/) - Initial setup guide * [iOS Builds](/docs/cli/cloud-build/ios/) - iOS-specific configuration * [Android Builds](/docs/cli/cloud-build/android/) - Android-specific configuration * [CLI Reference](/docs/cli/reference/build/) - Complete command documentation # Commands > Capgo CLI documentation, how to use it and what is used for ### Usage [Section titled “Usage”](#usage) All command should be run in your app folder with capacitor project ignited properly. [Capacitor Cross-platform native runtime for web apps ](https://capacitorjs.com/docs/getting-started/) ### **Init** [Section titled “Init”](#init) `npx @capgo/cli@latest init [apikey]` This method is here to onboard you step by step. It will add your app to Capgo. It will add the code to your app to validate the update. Likewise, it will build your app. Furthermore, it will upload your app to Capgo. And it will help you to check if the update works. ### **Login** [Section titled “Login”](#login) `npx @capgo/cli login [apikey]` This method is here to remember the `apikey` for you. Note use `--apikey=********` in any command to override it **Optionally you can give:** `--local` This will store your **apikey** in the local repo and git ignore it. ## **Doctor** [Section titled “Doctor”](#doctor) `npx @capgo/cli doctor` Command to check if you are up-to-date with Capgo packages. This command will also be useful for bug report. ## App [Section titled “App”](#app) ### **Add** [Section titled “Add”](#add) `npx @capgo/cli app add [appId]` `[appId]` your app ID the format `com.test.app` is explained [here](https://capacitorjs.com/docs/cli/commands/init/). > 💡 All option will be guessed in your config if not provided. Optionally, you can give: * `--icon [/path/to/my/icon]` to have a custom icon display in Capgo web app. * `--name [test]` to have a custom name in the list. * `--apikey [key]` API key to link to your account. * `--retention [retention]` retention period of app bundle in days, 0 by default = infinite. Example of `capacitor.config.json` for appId and AppName, the icon is guess in the resources folder ```json { "appId": "ee.forgr.capacitor_go", "appName": "Capgo", "webDir": "dist" } ``` ### **Set** [Section titled “Set”](#set) `npx @capgo/cli app set [appId]` `[appId]` is your app ID, the format is explained [here](https://capacitorjs.com/docs/cli/commands/init/). Optionally, you can give: * `--icon [/path/to/my/icon]` to have a custom icon display in Capgo web app. * `--name [test]` to have a custom name in the list. * `--retention [retention]` retention period of app bundle in days, 0 by default = infinite. * `--apikey [key]` API key to link to your account. ### **List** [Section titled “List”](#list) `npx @capgo/cli app list [appId]` `[appId]` your app ID the format `com.test.app` is explained [here](https://capacitorjs.com/docs/cli/commands/init/). Optionally, you can give: * `--apikey [key]` API key to link to your account. ### **Delete** [Section titled “Delete”](#delete) `npx @capgo/cli app delete [appId]` `[appId]` your app ID the format `com.test.app` is explained [here](https://capacitorjs.com/docs/cli/commands/init/). Optionally, you can give: * `--apikey [key]` API key to link to your account. * `--bundle` with the version number will only delete this version. ### Debug [Section titled “Debug”](#debug) `npx @capgo/cli app debug [appId]` `[appId]` your app ID the format `com.test.app` is explained [here](https://capacitorjs.com/docs/cli/commands/init/). Optionally, you can give: * `--apikey [key]` API key to link to your account. * `--device` with the specific device you want to debug ### Setting [Section titled “Setting”](#setting) `npx @capgo/cli app setting [path]` Edit the Capacitor config. `[path]` - path of the setting that you would like to change. For example, to change the `appId`, provide `appId`. If you wish to disable auto update in the `capacitor-updater` provide `plugins.CapacitorUpdater.autoUpdate` You MUST provide either `--string` or `--bool`! Options: * `--string ` - sets the setting to a string * `--bool ` - sets the setting to a boolean ## Bundle [Section titled “Bundle”](#bundle) ### Upload [Section titled “Upload”](#upload) `npx @capgo/cli bundle upload [appId]` `[appId]` is your app ID, the format is explained [here](https://capacitorjs.com/docs/cli/commands/init/). Optionally, you can give: * `--apikey ` API key to link to your account. * `--path ` Path of the folder to upload. * `--channel ` Channel to link to. * `--external ` Link to external URL instead of uploading to Capgo Cloud. * `--iv-session-key ` Set the IV and session key for bundle URL external. * `--s3-endpoint ` URL of S3 endpoint. Does not work with delta uploads or the external option. * `--s3-region ` Region for your S3 bucket. * `--s3-apikey ` API key for your S3 endpoint. * `--s3-apisecret ` API secret for your S3 endpoint. * `--s3-bucket-name ` Name for your AWS S3 bucket. * `--s3-port ` Port for your S3 endpoint. * `--no-s3-ssl` Disable SSL for S3 upload. * `--key ` Custom path for public signing key (v1 system). * `--key-data ` Public signing key (v1 system). * `--key-v2 ` Custom path for private signing key (v2 system). * `--key-data-v2 ` Private signing key (v2 system). * `--bundle-url` Prints bundle URL into stdout. * `--no-key` Ignore signing key and send clear update. * `--no-code-check` Ignore checking if notifyAppReady() is called in source code and index present in root folder. * `--display-iv-session` Show in the console the IV and session key used to encrypt the update. * `--bundle ` Bundle version number of the bundle to upload. * `--min-update-version ` Minimal version required to update to this version. Used only if the disable auto update is set to metadata in channel. * `--auto-min-update-version` Set the min update version based on native packages. * `--ignore-metadata-check` Ignores the metadata (node\_modules) check when uploading. * `--ignore-checksum-check` Ignores the checksum check when uploading. * `--timeout ` Timeout for the upload process in seconds. * `--delta` Uploads Delta (manifest) files alongside the full bundle. * `--delta-only` Uploads only Delta (manifest) updates, skipping the full bundle. * `--no-delta` Disables Delta (manifest) uploads (useful if `directUpdate` is enabled but you want a full bundle). * `--tus` Upload the bundle using tus protocol. * `--multipart` Uses multipart protocol to upload data to S3, Deprecated, use TUS instead. * `--encrypted-checksum ` An encrypted checksum (signature). Used only when uploading an external bundle. * `--package-json ` A path to package.json. Useful for monorepos. * `--auto-set-bundle` Set the bundle in capacitor.config.json. * `--node-modules ` A list of path to node\_modules. Useful for monorepos (comma separated ex: ../../node\_modules,./node\_modules) > ⭐️ External option helps to unlock 2 cases: corporate with privacy concern, don’t send the code to a third part and app bigger than 200 MB. With this setting, Capgo store only the link to the zip and sends the link to all apps. > 👀 Capgo cloud never looks at what is in the link (for external option), or in the code when stored. > 🔑 You can add a second layer of security by using encryption, then Capgo will not be able to look or modify anything, it becomes “trustless”. Example of `package.json` for version ```json { "version": "1.0.2" } ``` > ⛔ Version should be greater than “0.0.0”. > 💡 Don’t forget to update the version number each time you send one, version number cannot be overridden, or reused after deletion for security reason. ### **List** [Section titled “List”](#list-1) `npx @capgo/cli bundle list [appId]` `[appId]` your app ID the format `com.test.app` is explained [here](https://capacitorjs.com/docs/cli/commands/init/). Optionally, you can give: * `--apikey [key]` API key to link to your account. ### **Delete** [Section titled “Delete”](#delete-1) `npx @capgo/cli bundle delete [appId]` `[appId]` your app ID the format `com.test.app` is explained [here](https://capacitorjs.com/docs/cli/commands/init/). Optionally, you can give: * `--apikey [key]` API key to link to your account. * `--bundle` with the version number will only delete this version. ### Cleanup [Section titled “Cleanup”](#cleanup) in a SemVer range for a major version to Cloud `npx @capgo/cli bundle cleanup [appId] --bundle=[majorVersion] --keep=[numberToKeep]` `[appId]` your app ID the format `com.test.app` is explained [here](https://capacitorjs.com/docs/cli/commands/init/). Optionally, you can give: * `--apikey [key]` API key to link to your account. * `--bundle [majorVersion]` a version you wish to remove previous packages for, it will keep the last one + `numberToKeep`. * `--keep [numberToKeep]` the number of packages you wish to keep (default 4). For example: If you have 10 versions from 10.0.1 to 10.0.11, and you use `npx @capgo/cli cleanup [appId] --bundle=10.0.0` it will remove 10.0.1 to 10.0.6. 10.0.7 until 10.0.11 will be kept. If you have 20 versions in total, and you don’t provide a bundle number like this: `npx @capgo/cli cleanup [appId] --keep=2` It will remove 18 versions, and keep the last 2. > This command will ask for confirmation, it shows a table of what it will be keeping and removing. Note This command will ignore bundles which are currently in use in any channel. ### **Encrypt** [Section titled “Encrypt”](#encrypt) > **Warning**: This command is deprecated and will be removed in the next major release. Please use the new encryption system. `npx @capgo/cli bundle encrypt [path/to/zip]` This command is used when you use external source to store your code or for test purpose. Optionally, you can give: `--key [/path/to/my/private_key]` the path of your private key. `--key-data [privateKey]` the private key data, if you want to use inline. The command will print your `ivSessionKey`y and generate an encrypted zip, to use it with the upload command or decryt command. ### **Encrypt V2** [Section titled “Encrypt V2”](#encrypt-v2) `npx @capgo/cli bundle encrypt [path/to/zip] [checksum]` This command is used when you use external source to store your code or for test purpose. The checksum is the sha256 of the bundle (generated by —key-v2), it is used to verify the integrity of the file after decryption. It will be enncrypted with the private key and sent along with the bundle. In encryption v2 the checksum is upgraded to become a “signature” of the bundle. Optionally, you can give: `--key [/path/to/my/private_key]` the path of your private key. `--key-data [privateKey]` the private key data, if you want to use inline. `--json` to output info as json. The command will print your `ivSessionKey`y and generate an encrypted zip, to use it with the upload command or decryt command. ### **Decrypt** [Section titled “Decrypt”](#decrypt) `npx @capgo/cli bundle decrypt [path/to/zip] [ivSessionKey]` Optionally, you can give: `--key [/path/to/my/private_key]` the path of your private key. `--key-data [privateKey]` the private key data, if you want to use inline. This command is mainly used for test purpose, it will decrypt the zip and print the base64 decrypted session key in the console. ### **Decrypt V2** [Section titled “Decrypt V2”](#decrypt-v2) `npx @capgo/cli bundle decryptV2 [path/to/zip] [ivSessionKey]` Optionally, you can give: `--key [/path/to/my/private_key]` the path of your private key. `--key-data [privateKey]` the private key data, if you want to use inline. This command is mainly used for test purpose, it will decrypt the zip and print the base64 decrypted session key in the console. `--checksum [checksum]` the checksum of the file, it will verify the checksum after decryption. ### **Zip** [Section titled “Zip”](#zip) `npx @capgo/cli bundle zip [appId]` `[appId]` is your app ID, the format is explained [here](https://capacitorjs.com/docs/cli/commands/init/). Optionally, you can give: * `--path [/path/to/my/bundle]` to upload a specific folder. * `--bundle [1.0.0]` to set the bundle version number of the filename. * `--name [myapp]` to override the filename. * `--json` to output info as json. * `--no-code-check` to ignore the code check and send the bundle anyway. * `--key-v2` to use the new encryption system. This is required as new encryption system use better checksums to verify the integrity of the file. ### **Compatibility** [Section titled “Compatibility”](#compatibility) `npx @capgo/cli bundle compatibility [appId] -c [channelId]` `[appId]` is your app ID, the format is explained [here](https://capacitorjs.com/docs/cli/commands/init/). `[channelId]` the name of your new channel. Optionally, you can give: * `--apikey [key]` API key to link to your account. * `--text` use text instead of emojis in the table * `--channel [channel]` the channel to check the compatibility with. * `--package-json ` A path to package.json. Useful for monorepos * `--node-modules ` A list of path to node\_modules. Useful for monorepos (comma separated ex: ../../node\_modules,./node\_modules) ## Channel [Section titled “Channel”](#channel) ### **Add** [Section titled “Add”](#add-1) `npx @capgo/cli channel add [channelId] [appId]` `[channelId]` the name of your new channel. `[appId]` your app ID the format `com.test.app` is explained [here](https://capacitorjs.com/docs/cli/commands/init/). ### **Delete** [Section titled “Delete”](#delete-2) `npx @capgo/cli channel delete [channelId] [appId]` `[channelId]` the name of your channel you want to delete. `[appId]` your app ID the format `com.test.app` is explained [here](https://capacitorjs.com/docs/cli/commands/init/). ### **List** [Section titled “List”](#list-2) `npx @capgo/cli channel list [appId]` `[appId]` your app ID the format `com.test.app` is explained [here](https://capacitorjs.com/docs/cli/commands/init/). Optionally, you can give: * `--apikey [key]` API key to link to your account. ### **Set** [Section titled “Set”](#set-1) `npx @capgo/cli channel set [channelId] [appId]` `[appId]` is your app ID, the format is explained [here](https://capacitorjs.com/docs/cli/commands/init/). Optionally, you can give: * `--bundle [1.2.3]` your app bundle already sent to the cloud, to link it to a channel. * `--latest` get the bundle version from `package.json:version`, cannot be used with `--bundle`. * `--state [ normal | default ]` set the channel state, can be `normal` or `default`. One channel needs to be `default`. * `--downgrade` allows the channel to send downgrade version to devices. * `--no-downgrade` disallows the channel to send downgrade version to devices. * `--upgrade` allows the channel to send upgrade (major) version to devices. * `--no-upgrade` disallow the channel to send upgrade (major) version to devices. * `--ios` allows the channel to send version to iOS devices. * `--no-ios` disallows the channel to send version to iOS devices. * `--android` allows the channel to send version to android devices. * `--no-android` disallows the channel to send version to android devices. * `--self-assign` allows devices to self assign to this channel. * `--no-self-assign` disallows devices to self assign to this channel. * `--disable-auto-update STRATEGY` Disable auto update strategy for this channel. The possible options are: major, minor, metadata, none. * `--apikey [key]` API key to link to your account. ## Disable updates strategy [Section titled “Disable updates strategy”](#disable-updates-strategy) There are a few ways to handle disabling updates for too old versions.\ Capgo cannot update native code thus an update from a version with the old native code to a version with the updated native code should not be possible. There are a couple of ways to achieve that. First, the `major` strategy. It prevents an update from `0.0.0` -> `1.0.0`. The major is the highlighted number (**1**.0.0 and **0**.0.0).\ Second is the `minor` strategy. It prevents an update from `0.0.0` -> `1.1.0` or an update from `1.1.0` to `1.2.0`. **BE AWARE** this strategy does not prevent an update from `0.1.0` -> `1.1.0` Third, the `patch` strategy. It was added into capgo as a very strict mode. It’s not recommended to be used unless you fully understand how it works. In order for it to accept a update the following conditions must be meet: * The major is the same between the new and the old version * The minor is the same between the new and the old version * The patch of the new version if greater then the patch of the old version Here is an example of which scenarios the update is allowed or denied * 0.0.311 -> 0.0.314 ✅ * 0.0.0 -> 0.0.314 ✅ * 0.0.316 -> 0.0.314 ❌ * 0.1.312 -> 0.0.314 ❌ * 1.0.312 -> 0.0.314 ❌ Lastly the most complicated strategy. The `metadata` strategy.\ First you need to know that initially after you enable it the updates **WILL** fail as the channel is lacking the required metadata.\ If the channel is lacking metadata you will see a message like this: ![Cannot find metadata](/fail-metadata.webp) If you see something like this you know that you have to go to the current bundle for the failing channel and set the metadata.\ First, figure out what channel is failing. You can do that by looking at the `misconfigured` column ![Misconfigured table](/misconfigured-table.webp) Then go to the failing channel and click on `Bundle number`. This should take you to the bundle page. ![Locate failing channel](/fail-channel-show.webp) Once there fill the `Minimal update version` field. This should be a [semver](https://devhints.io/semver/).\ If the value you pass is not a semver you will get an error, but if everything goes correctly you should see something like this: ![Set min version](/set-min-update-version.webp) Now, you likely do not want to set this data manually every time you update. Fortunately, the CLI will prevent you from sending an update without this metadata ![CLI fail no metadata](/cli-fail-no-metadata.webp) To properly upload a bundle when using the `metadata` option you need to pass the `--min-update-version` with the valid semver. Something like this: ![CLI upload with metadata](/cli-upload-with-metadata.webp) The `--min-update-version` is not the ONLY way to do compatibility. There also exists the `--auto-min-update-version`. Here is how it works. First, it takes a look at the version currently uploaded to the channel. It checks compatibility same as `bundle compatibility` command would. Second, if the new version is 100% compatible it reuses the `min_update_version` from the latest version in the channel. If not, then it sets the `min_update_version` to the bundle number of the newly uploaded version. You will always get an information what is the `min_update_version` when using this option. It will look something like this: ![Min update version](/min_update_version_info.webp) If the new version is not compatible it should look something like this ![Min update version not compatible](/min_update_version_not_compatible.webp) ## End-to-End encryption (Trustless) [Section titled “End-to-End encryption (Trustless)”](#end-to-end-encryption-trustless) Capgo supports end-to-end encryption, this means that your bundle(code) is encrypted before sent to the cloud and decrypted on the device. For that, you need to generate an RSA key pair, you can use the following command to generate it. The encryption system is a combination of RSA and AES, the RSA key is used to encrypt the AES key, and the AES key is used to encrypt the file. See below for more information about the encryption system. ![How crypto works](/crypto_explained.webp) Encryption schema ### Create key for your app [Section titled “Create key for your app”](#create-key-for-your-app) `npx @capgo/cli key create` Optionally, you can give: `--force` to overwrite the existing key. This command will create for you a key pair in your app, and will ask you to save the private key in a safe place. It’s recommended to not git commit the private key, and to not share it with anyone. > After your local test, remove the key from the config file and add it on the CI step with `key save` ### Save key in your app config [Section titled “Save key in your app config”](#save-key-in-your-app-config) `npx @capgo/cli key save` Optionally, you can give: `--key [/path/to/my/public_key]` the path of your public key file. `--key-data [publicKey]` the public key data, if you want to use inline. This command is useful if you followed the recommendation and didn’t commit the key in your app config. ## Ci integration [Section titled “Ci integration”](#ci-integration) To automate your work, I recommend you make GitHub action do the job of pushing to our server [GitHub action tutorial](https://capgo.app/blog/automatic-build-and-release-with-github-actions/) ## Our demo app [Section titled “Our demo app”](#our-demo-app) [GitHub - Cap-go/demo-app](https://github.com/Cap-go/demo-app/) Don’t forget to configure CI env variable with your API key # CLI From 0.x to 1.x > How to upgrade from 0.x to 1.x, of the updater of Capgo, learn what are the breaking changes and how to handle them There are no significant changes in the CLI. The breaking change is mainly the rename of the argument `--version` to `--bundle` to avoid conflict, and follow the new naming everywhere. # Encryption > How to encrypt your data with encryption v2, secure your app and ensure only you can update your users with your updates This documentation explains how to migrate to the encryption v2 system. Learn more about the encryption v2 system in the [blog post](/blog/introducing-end-to-end-security-to-capacitor-updater-with-code-signing). ## 1. Create Key Pair [Section titled “1. Create Key Pair”](#1-create-key-pair) ```bash npx @capgo/cli key create ``` Store the private key securely. Never commit it to source control or share it with untrusted parties. This command: * Creates a new key pair in your app * Removes the old key from your Capacitor config * Keeps old key files for backward compatibility ## 2. Update Capacitor Config [Section titled “2. Update Capacitor Config”](#2-update-capacitor-config) When prompted “Do you want to setup encryption with the new channel in order to support old apps and facilitate the migration?”, select yes. This adds a new `defaultChannel` option to your Capacitor config. capacitor.config.ts ```ts import { CapacitorConfig } from '@capacitor/cli'; const config: CapacitorConfig = { appId: 'com.example.app', appName: 'Example App', plugins: { CapacitorUpdater: { // ... other options defaultChannel: 'encryption_v2' // New apps will use this channel } } }; export default config; ``` ## 3. Upload Bundle to New Channel [Section titled “3. Upload Bundle to New Channel”](#3-upload-bundle-to-new-channel) ```bash npx @capgo/cli bundle upload --channel encryption_v2 ``` ## 4. Enable Self-Assignment [Section titled “4. Enable Self-Assignment”](#4-enable-self-assignment) Caution Required for the `defaultChannel` option to work ```bash npx @capgo/cli channel set encryption_v2 --self-assign ``` ## 5. Upload to Old Channel [Section titled “5. Upload to Old Channel”](#5-upload-to-old-channel) ```bash npx @capgo/cli bundle upload --channel production ``` Tip Capacitor config is never uploaded to Capgo ## 6. Cleanup (After 3-4 Months) [Section titled “6. Cleanup (After 3-4 Months)”](#6-cleanup-after-3-4-months) Once all users have updated their apps: 1. Remove `defaultChannel` from your Capacitor config 2. Delete the old channel: ```bash npx @capgo/cli channel delete encryption_v2 ``` Note Apps using `encryption_v2` as default will switch to `production` channel after deletion # Overview > This document provides a comprehensive overview of the Capgo CLI, how it can be utilized to enhance your app development process by enabling seamless live updates Use Capgo’s Live Updates feature to update the JavaScript bundles of your app remotely, in real-time. Push JS updates directly to your users without going through the app store review process to instantly fix bugs and ship new features. Note Live Updates are limited to JavaScript bundle changes. If you need to update native code, such as adding or removing a plugin or changing native project configuration, you’ll need to submit a new native binary build to the app stores. ## How Live Updates Work [Section titled “How Live Updates Work”](#how-live-updates-work) Capgo’s Live Update system has two key components: 1. The Capgo SDK, which you install in your app. The SDK checks for available updates and downloads them in the background. 2. Channels, which let you target updates to specific groups of users. You can use channels to manage different release tracks, such as `Production`, `Staging`, and `Dev`. When you upload a new JS bundle to Capgo and assign it to a channel, the Capgo SDK in apps configured for that channel will detect the update and download it. The next time the app restarts, the new bundle will be loaded. ## Getting Started [Section titled “Getting Started”](#getting-started) To start using Live Updates, follow these steps: 1. Complete the [Capgo Quickstart](/docs/getting-started/quickstart) to set up your app in Capgo and install the Capgo SDK. 2. In your app code, call `CapacitorUpdater.notifyAppReady()` after your app has finished initializing. This tells the Capgo SDK that your app is ready to receive updates. 3. Build your JS bundle and upload it to Capgo: ```shell npm run build npx @capgo/cli@latest bundle upload --channel=production ``` 4. Open your app and wait for the update to download. You can check the status with: ```shell npx @capgo/cli@latest app debug ``` 5. Once the update is downloaded, close and reopen your app to load the new bundle. See the [Deploying Live Updates](/docs/getting-started/deploy) guide for more details. ## The Capgo CLI [Section titled “The Capgo CLI”](#the-capgo-cli) The Capgo CLI is a powerful tool that allows developers to interact with Capgo’s services from their own CI/CD pipelines. With the CLI, you have granular control over when builds are produced and deployed, enabling you to integrate Capgo into your existing enterprise workflows. ### What is the Capgo CLI for? [Section titled “What is the Capgo CLI for?”](#what-is-the-capgo-cli-for) The Capgo CLI is designed for developers and teams who need more control and flexibility in their live update workflows. By using the CLI in your CI/CD pipelines, you can: * Decide exactly when to build and deploy updates, rather than relying on Capgo’s built-in automation * Insert your own processes, such as code signing, QA testing, or manager approvals, between the build and deploy steps * Integrate Capgo into your existing DevOps tooling and workflows ### Authentication [Section titled “Authentication”](#authentication) To use the Capgo CLI, you’ll need to authenticate with your API key. You can generate an API key in your Capgo account settings. To log in and securely store your API key, run: ```shell npx @capgo/cli@latest login [API_KEY] ``` This command will then be saved for future use. You won’t need to provide your API key with each command after logging in. ### Key Differences from Other CLI Tools [Section titled “Key Differences from Other CLI Tools”](#key-differences-from-other-cli-tools) If you’re familiar with other live update CLI tools, there are a few key things to note about Capgo’s CLI: * Capgo uses a single CLI for both development and CI/CD use cases, as Capgo is focused solely on the live update feature set. * The Capgo CLI doesn’t require a separate installation step. It’s bundled with the `@capgo/cli` package and can be run directly using `npx`. * Capgo’s CLI is designed specifically for the live update workflow, so it may not include some features or commands found in more general-purpose CLI tools. ## Next Steps [Section titled “Next Steps”](#next-steps) [ Channels](/docs/live-updates/channels/) [Learn how to use channels to manage different release tracks and target updates to specific users.](/docs/live-updates/channels/) [ Rollbacks](/docs/live-updates/rollbacks/) [Discover how to roll back to a previous JS bundle version if an update causes issues.](/docs/live-updates/rollbacks/) [ Update Behavior](/docs/live-updates/update-behavior/) [Customize how and when updates are downloaded and applied in your app.](/docs/live-updates/update-behavior/) [ Fast Updates](/docs/live-updates/differentials/) [Learn how to use fast updates to speed up the update process.](/docs/live-updates/differentials/) # 👤 account > 👤 Manage your Capgo account details and retrieve information for support or collaboration. 👤 Manage your Capgo account details and retrieve information for support or collaboration. ### []()🔹 **Id** [Section titled “ 🔹 Id”](#--id) ```bash npx @capgo/cli@latest account id ``` 🪪 Retrieve your account ID, safe to share for collaboration or support purposes in Discord or other platforms. **Example:** ```bash npx @capgo/cli@latest account id ``` **Options:** | Param | Type | Description | | ------- | -------- | ------------------------------- | | **-a,** | `string` | API key to link to your account | # 📱 app > 📱 Manage your Capgo app settings and configurations in Capgo Cloud. 📱 Manage your Capgo app settings and configurations in Capgo Cloud. ### []()➕ **Add** [Section titled “ ➕ Add”](#--add) **Alias:** `a` ```bash npx @capgo/cli@latest app add ``` ➕ Add a new app to Capgo Cloud with a unique app ID in the format com.test.app. All options can be guessed from config if not provided. **Example:** ```bash npx @capgo/cli@latest app add com.example.app --name "My App" --icon ./icon.png ``` **Options:** | Param | Type | Description | | -------------- | -------- | ---------------------------------------------------------------- | | **-n,** | `string` | App name for display in Capgo Cloud | | **-i,** | `string` | App icon path for display in Capgo Cloud | | **-a,** | `string` | API key to link to your account | | **—supa-host** | `string` | Custom Supabase host URL (for self-hosting or Capgo development) | | **—supa-anon** | `string` | Custom Supabase anon key (for self-hosting) | ### []()🗑️ **Delete** [Section titled “ 🗑️ Delete”](#-️-delete) ```bash npx @capgo/cli@latest app delete ``` 🗑️ Delete an app from Capgo Cloud, optionally specifying a version to delete only that bundle. **Example:** ```bash npx @capgo/cli@latest app delete com.example.app ``` **Options:** | Param | Type | Description | | -------------- | -------- | ---------------------------------------------------------------- | | **-a,** | `string` | API key to link to your account | | **—supa-host** | `string` | Custom Supabase host URL (for self-hosting or Capgo development) | | **—supa-anon** | `string` | Custom Supabase anon key (for self-hosting) | ### []()📋 **List** [Section titled “ 📋 List”](#--list) **Alias:** `l` ```bash npx @capgo/cli@latest app list ``` 📋 List all apps registered under your account in Capgo Cloud. **Example:** ```bash npx @capgo/cli@latest app list ``` **Options:** | Param | Type | Description | | -------------- | -------- | ---------------------------------------------------------------- | | **-a,** | `string` | API key to link to your account | | **—supa-host** | `string` | Custom Supabase host URL (for self-hosting or Capgo development) | | **—supa-anon** | `string` | Custom Supabase anon key (for self-hosting) | ### []()🐞 **Debug** [Section titled “ 🐞 Debug”](#--debug) ```bash npx @capgo/cli@latest app debug ``` 🐞 Listen for live update events in Capgo Cloud to debug your app. Optionally target a specific device for detailed diagnostics. **Example:** ```bash npx @capgo/cli@latest app debug com.example.app --device DEVICE_ID ``` **Options:** | Param | Type | Description | | -------------- | -------- | ---------------------------------------------------------------- | | **-a,** | `string` | API key to link to your account | | **-d,** | `string` | The specific device ID to debug | | **—supa-host** | `string` | Custom Supabase host URL (for self-hosting or Capgo development) | | **—supa-anon** | `string` | Custom Supabase anon key (for self-hosting) | ### []()⚙️ **Setting** [Section titled “ ⚙️ Setting”](#-️-setting) ```bash npx @capgo/cli@latest app setting ``` ⚙️ Modify Capacitor configuration programmatically. Specify setting path (e.g., plugins.CapacitorUpdater.defaultChannel) with —string or —bool. **Example:** ```bash npx @capgo/cli@latest app setting plugins.CapacitorUpdater.defaultChannel --string "Production" ``` **Options:** | Param | Type | Description | | ----------- | -------- | ----------------------------------------------------------------------- | | **—bool** | `string` | A value for the setting to modify as a boolean, ex: —bool true | | **—string** | `string` | A value for the setting to modify as a string, ex: —string “Production” | ### []()⚙️ **Set** [Section titled “ ⚙️ Set”](#-️-set) **Alias:** `s` ```bash npx @capgo/cli@latest app set ``` ⚙️ Update settings for an existing app in Capgo Cloud, such as name, icon, or retention period for bundles. Retention of 0 means infinite storage. **Example:** ```bash npx @capgo/cli@latest app set com.example.app --name "Updated App" --retention 30 ``` **Options:** | Param | Type | Description | | -------------------- | -------- | ------------------------------------------------------------------------------------ | | **-n,** | `string` | App name for display in Capgo Cloud | | **-i,** | `string` | App icon path for display in Capgo Cloud | | **-a,** | `string` | API key to link to your account | | **-r,** | `string` | Days to keep old bundles (0 = infinite, default: 0) | | **—expose-metadata** | `string` | Expose bundle metadata (link and comment) to the plugin (true/false, default: false) | | **—supa-host** | `string` | Custom Supabase host URL (for self-hosting or Capgo development) | | **—supa-anon** | `string` | Custom Supabase anon key (for self-hosting) | # 🔹 build > 🏗️ Manage native iOS/Android builds through Capgo Cloud. 🏗️ Manage native iOS/Android builds through Capgo Cloud. ### []()🚀 **Init** [Section titled “ 🚀 Init”](#--init) **Alias:** `onboarding` ```bash npx @capgo/cli@latest build init ``` Set up iOS build credentials interactively (creates certificates and profiles automatically) ### []()🔹 **Request** [Section titled “ 🔹 Request”](#--request) ```bash npx @capgo/cli@latest build request ``` Request a native build from Capgo Cloud. This command will zip your project directory and upload it to Capgo for building. The build will be processed and sent directly to app stores. 🔒 SECURITY: Credentials are never stored on Capgo servers. They are auto-deleted after build completion. Build outputs may optionally be uploaded for time-limited download links. 📋 PREREQUISITE: Save credentials first with: `npx @capgo/cli build credentials save --appId --platform ` **Example:** ```bash npx @capgo/cli@latest build request com.example.app --platform ios --path . ``` **Options:** | Param | Type | Description | | -------------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------ | | **—path** | `string` | Path to the project directory to build (default: current directory) | | **—platform** | `string` | Target platform: ios or android (required) | | **—build-mode** | `string` | Build mode: debug or release (default: release) | | **—build-certificate-base64** | `string` | iOS: Base64-encoded .p12 certificate | | **—p12-password** | `string` | iOS: Certificate password (optional if cert has no password) | | **—apple-id** | `string` | iOS: Apple ID email | | **—apple-app-specific-password** | `string` | iOS: App-specific password | | **—apple-key-id** | `string` | iOS: App Store Connect API Key ID | | **—apple-issuer-id** | `string` | iOS: App Store Connect Issuer ID | | **—apple-key-content** | `string` | iOS: Base64-encoded App Store Connect API key (.p8) | | **—app-store-connect-team-id** | `string` | iOS: App Store Connect Team ID | | **—ios-scheme** | `string` | iOS: Xcode scheme to build (default: App) | | **—ios-target** | `string` | iOS: Xcode target for reading build settings (default: same as scheme) | | **—ios-distribution** | `string` | iOS: Distribution mode | | **—ios-provisioning-profile** | `string` | iOS: Provisioning profile path or bundleId=path mapping (repeatable) | | **—android-keystore-file** | `string` | Android: Base64-encoded keystore file | | **—keystore-key-alias** | `string` | Android: Keystore key alias | | **—keystore-key-password** | `string` | Android: Keystore key password | | **—keystore-store-password** | `string` | Android: Keystore store password | | **—play-config-json** | `string` | Android: Base64-encoded Google Play service account JSON | | **—android-flavor** | `string` | Android: Product flavor to build (e.g. production). Required if your project has multiple flavors. | | **—no-playstore-upload** | `boolean` | Skip Play Store upload for this build (nulls out saved play config). Requires —output-upload. | | **—output-upload** | `boolean` | Override output upload behavior for this build only (enable). Precedence: CLI > env > saved credentials | | **—no-output-upload** | `boolean` | Override output upload behavior for this build only (disable). Precedence: CLI > env > saved credentials | | **—output-retention** | `string` | Override output link TTL for this build only (1h to 7d). Examples: 1h, 6h, 2d. Precedence: CLI > env > saved credentials | | **—skip-build-number-bump** | `boolean` | Skip automatic build number/version code incrementing. Uses whatever version is already in the project files. | | **—no-skip-build-number-bump** | `boolean` | Override saved credentials to re-enable automatic build number incrementing for this build only. | | **-a,** | `string` | API key to link to your account | | **—supa-host** | `string` | Custom Supabase host URL (for self-hosting or Capgo development) | | **—supa-anon** | `string` | Custom Supabase anon key (for self-hosting) | | **—verbose** | `boolean` | Enable verbose output with detailed logging | ### []()🔹 **Credentials** [Section titled “ 🔹 Credentials”](#--credentials) ```bash npx @capgo/cli@latest build credentials ``` Manage build credentials stored locally on your machine. 🔒 SECURITY: * Credentials saved to \~/.capgo-credentials/credentials.json (global) or .capgo-credentials.json (local) * When building, sent to Capgo but NEVER stored permanently * Deleted from Capgo immediately after build * Build outputs may optionally be uploaded for time-limited download links 📚 DOCUMENTATION: iOS setup: Android setup: # 📦 bundle > 📦 Manage app bundles for deployment in Capgo Cloud, including upload, compatibility checks, and encryption. 📦 Manage app bundles for deployment in Capgo Cloud, including upload, compatibility checks, and encryption. ### []()⬆️ **Upload** [Section titled “ ⬆️ Upload”](#-️-upload) **Alias:** `u` ```bash npx @capgo/cli@latest bundle upload ``` ⬆️ Upload a new app bundle to Capgo Cloud for distribution. Version must be > 0.0.0 and unique. Deleted versions cannot be reused for security. External option: Store only a URL link (useful for apps >200MB or privacy requirements). Capgo never inspects external content. Add encryption for trustless security. **Example:** ```bash npx @capgo/cli@latest bundle upload com.example.app --path ./dist --channel production ``` **Options:** | Param | Type | Description | | ----------------------------------- | --------- | --------------------------------------------------------------------------------------------------------------------------------- | | **-a,** | `string` | API key to link to your account | | **-p,** | `string` | Path of the folder to upload, if not provided it will use the webDir set in capacitor.config | | **-c,** | `string` | Channel to link to | | **-e,** | `string` | Link to external URL instead of upload to Capgo Cloud | | **—iv-session-key** | `string` | Set the IV and session key for bundle URL external | | **—s3-region** | `string` | Region for your S3 bucket | | **—s3-apikey** | `string` | API key for your S3 endpoint | | **—s3-apisecret** | `string` | API secret for your S3 endpoint | | **—s3-endpoint** | `string` | URL of S3 endpoint | | **—s3-bucket-name** | `string` | Name for your AWS S3 bucket | | **—s3-port** | `string` | Port for your S3 endpoint | | **—no-s3-ssl** | `boolean` | Disable SSL for S3 upload | | **—key-v2** | `string` | Custom path for private signing key (v2 system) | | **—key-data-v2** | `string` | Private signing key (v2 system) | | **—bundle-url** | `boolean` | Prints bundle URL into stdout | | **—no-key** | `boolean` | Ignore signing key and send clear update | | **—no-code-check** | `boolean` | Ignore checking if notifyAppReady() is called in source code and index present in root folder | | **—display-iv-session** | `boolean` | Show in the console the IV and session key used to encrypt the update | | **-b,** | `string` | Bundle version number of the bundle to upload | | **—link** | `string` | Link to external resource (e.g. GitHub release) | | **—comment** | `string` | Comment about this version, could be a release note, a commit hash, a commit message, etc. | | **—min-update-version** | `string` | Minimal version required to update to this version. Used only if the disable auto update is set to metadata in channel | | **—auto-min-update-version** | `boolean` | Set the min update version based on native packages | | **—ignore-metadata-check** | `boolean` | Ignores the metadata (node\_modules) check when uploading | | **—ignore-checksum-check** | `boolean` | Ignores the checksum check when uploading | | **—force-crc32-checksum** | `boolean` | Force CRC32 checksum for upload (override auto-detection) | | **—timeout** | `string` | Timeout for the upload process in seconds | | **—multipart** | `boolean` | \[DEPRECATED] Use —tus instead. Uses multipart protocol for S3 uploads | | **—zip** | `boolean` | Upload the bundle using zip to Capgo cloud (legacy) | | **—tus** | `boolean` | Upload the bundle using TUS to Capgo cloud | | **—tus-chunk-size** | `string` | Chunk size in bytes for TUS resumable uploads (default: auto) | | **—partial** | `boolean` | \[DEPRECATED] Use —delta instead. Upload incremental updates | | **—partial-only** | `boolean` | \[DEPRECATED] Use —delta-only instead. Upload only incremental updates, skip full bundle | | **—delta** | `boolean` | Upload delta updates (only changed files) for instant, super fast updates instead of big zip downloads | | **—delta-only** | `boolean` | Upload only delta updates without full bundle for maximum speed (useful for large apps) | | **—no-delta** | `boolean` | Disable delta updates even if Direct Update is enabled | | **—encrypted-checksum** | `string` | An encrypted checksum (signature). Used only when uploading an external bundle. | | **—auto-set-bundle** | `boolean` | Set the bundle in capacitor.config.json | | **—dry-upload** | `boolean` | Dry upload the bundle process, mean it will not upload the files but add the row in database (Used by Capgo for internal testing) | | **—package-json** | `string` | Paths to package.json files for monorepos (comma-separated) | | **—node-modules** | `string` | Paths to node\_modules directories for monorepos (comma-separated) | | **—encrypt-partial** | `boolean` | Encrypt delta update files (auto-enabled for updater > 6.14.4) | | **—delete-linked-bundle-on-upload** | `boolean` | Locates the currently linked bundle in the channel you are trying to upload to, and deletes it | | **—no-brotli-patterns** | `string` | Files to exclude from Brotli compression (comma-separated globs, e.g., “*.jpg,*.png”) | | **—disable-brotli** | `boolean` | Completely disable brotli compression even if updater version supports it | | **—version-exists-ok** | `boolean` | Exit successfully if bundle version already exists, useful for CI/CD workflows with monorepos | | **—self-assign** | `boolean` | Allow devices to auto-join this channel (updates channel setting) | | **—supa-host** | `string` | Custom Supabase host URL (for self-hosting or Capgo development) | | **—supa-anon** | `string` | Custom Supabase anon key (for self-hosting) | | **—verbose** | `boolean` | Enable verbose output with detailed logging | ### []()🧪 **Compatibility** [Section titled “ 🧪 Compatibility”](#--compatibility) ```bash npx @capgo/cli@latest bundle compatibility ``` 🧪 Check compatibility of a bundle with a specific channel in Capgo Cloud to ensure updates are safe. **Example:** ```bash npx @capgo/cli@latest bundle compatibility com.example.app --channel production ``` **Options:** | Param | Type | Description | | ----------------- | --------- | ------------------------------------------------------------------ | | **-a,** | `string` | API key to link to your account | | **-c,** | `string` | Channel to check the compatibility with | | **—text** | `boolean` | Output text instead of emojis | | **—package-json** | `string` | Paths to package.json files for monorepos (comma-separated) | | **—node-modules** | `string` | Paths to node\_modules directories for monorepos (comma-separated) | | **—supa-host** | `string` | Custom Supabase host URL (for self-hosting or Capgo development) | | **—supa-anon** | `string` | Custom Supabase anon key (for self-hosting) | ### []()🔹 **ReleaseType** [Section titled “ 🔹 ReleaseType”](#--releasetype) ```bash npx @capgo/cli@latest bundle releaseType ``` 🧭 Print “native” or “OTA” based on compatibility with a channel’s latest metadata. **Example:** ```bash npx @capgo/cli@latest bundle releaseType com.example.app --channel production ``` **Options:** | Param | Type | Description | | ----------------- | -------- | ------------------------------------------------------------------ | | **-a,** | `string` | API key to link to your account | | **-c,** | `string` | Channel to compare against | | **—package-json** | `string` | Paths to package.json files for monorepos (comma-separated) | | **—node-modules** | `string` | Paths to node\_modules directories for monorepos (comma-separated) | | **—supa-host** | `string` | Custom Supabase host URL (for self-hosting or Capgo development) | | **—supa-anon** | `string` | Custom Supabase anon key (for self-hosting) | ### []()🗑️ **Delete** [Section titled “ 🗑️ Delete”](#-️-delete) **Alias:** `d` ```bash npx @capgo/cli@latest bundle delete ``` 🗑️ Delete a specific bundle from Capgo Cloud, optionally targeting a single version. **Example:** ```bash npx @capgo/cli@latest bundle delete BUNDLE_ID com.example.app ``` **Options:** | Param | Type | Description | | -------------- | -------- | ---------------------------------------------------------------- | | **-a,** | `string` | API key to link to your account | | **—supa-host** | `string` | Custom Supabase host URL (for self-hosting or Capgo development) | | **—supa-anon** | `string` | Custom Supabase anon key (for self-hosting) | ### []()📋 **List** [Section titled “ 📋 List”](#--list) **Alias:** `l` ```bash npx @capgo/cli@latest bundle list ``` 📋 List all bundles uploaded for an app in Capgo Cloud. **Example:** ```bash npx @capgo/cli@latest bundle list com.example.app ``` **Options:** | Param | Type | Description | | -------------- | -------- | ---------------------------------------------------------------- | | **-a,** | `string` | API key to link to your account | | **—supa-host** | `string` | Custom Supabase host URL (for self-hosting or Capgo development) | | **—supa-anon** | `string` | Custom Supabase anon key (for self-hosting) | ### []()🧹 **Cleanup** [Section titled “ 🧹 Cleanup”](#--cleanup) **Alias:** `c` ```bash npx @capgo/cli@latest bundle cleanup ``` 🧹 Delete old bundles in Capgo Cloud, keeping specified number of recent versions. Bundles linked to channels are preserved unless —ignore-channel is used. **Example:** ```bash npx @capgo/cli@latest bundle cleanup com.example.app --bundle=1.0 --keep=3 ``` **Options:** | Param | Type | Description | | ------------------- | --------- | ------------------------------------------------------------------------- | | **-b,** | `string` | Bundle version number of the app to delete | | **-a,** | `string` | API key to link to your account | | **-k,** | `string` | Number of versions to keep | | **-f,** | `string` | Force removal | | **—ignore-channel** | `boolean` | Delete bundles even if linked to channels (WARNING: deletes channels too) | | **—supa-host** | `string` | Custom Supabase host URL (for self-hosting or Capgo development) | | **—supa-anon** | `string` | Custom Supabase anon key (for self-hosting) | ### []()🔒 **Encrypt** [Section titled “ 🔒 Encrypt”](#--encrypt) ```bash npx @capgo/cli@latest bundle encrypt ``` 🔒 Encrypt a zip bundle for secure external storage. Returns ivSessionKey for upload/decryption. Get checksum using ‘bundle zip —json’. **Example:** ```bash npx @capgo/cli@latest bundle encrypt ./myapp.zip CHECKSUM ``` **Options:** | Param | Type | Description | | ----------------- | -------- | ----------------------------------------------------------- | | **—key** | `string` | Custom path for private signing key | | **—key-data** | `string` | Private signing key | | **-j,** | `string` | Output in JSON | | **—package-json** | `string` | Paths to package.json files for monorepos (comma-separated) | ### []()🔓 **Decrypt** [Section titled “ 🔓 Decrypt”](#--decrypt) ```bash npx @capgo/cli@latest bundle decrypt ``` 🔓 Decrypt an encrypted bundle (mainly for testing). Prints base64 session key for verification. **Example:** ```bash npx @capgo/cli@latest bundle decrypt ./myapp_encrypted.zip CHECKSUM ``` **Options:** | Param | Type | Description | | ----------------- | -------- | ------------------------------------------------------------- | | **—key** | `string` | Custom path for private signing key | | **—key-data** | `string` | Private signing key | | **—checksum** | `string` | Checksum of the bundle, to verify the integrity of the bundle | | **—package-json** | `string` | Paths to package.json files for monorepos (comma-separated) | ### []()🔹 **Zip** [Section titled “ 🔹 Zip”](#--zip) ```bash npx @capgo/cli@latest bundle zip ``` 🗜️ Create a zip file of your app bundle. Returns checksum for use with encryption. Use —json for machine-readable output. **Example:** ```bash npx @capgo/cli@latest bundle zip com.example.app --path ./dist ``` **Options:** | Param | Type | Description | | ------------------ | --------- | --------------------------------------------------------------------------------------------- | | **-p,** | `string` | Path of the folder to upload, if not provided it will use the webDir set in capacitor.config | | **-b,** | `string` | Bundle version number to name the zip file | | **-n,** | `string` | Name of the zip file | | **-j,** | `string` | Output in JSON | | **—no-code-check** | `boolean` | Ignore checking if notifyAppReady() is called in source code and index present in root folder | | **—key-v2** | `boolean` | Use encryption v2 | | **—package-json** | `string` | Paths to package.json files for monorepos (comma-separated) | # 📢 channel > 📢 Manage distribution channels for app updates in Capgo Cloud, controlling how updates are delivered to devices. 📢 Manage distribution channels for app updates in Capgo Cloud, controlling how updates are delivered to devices. ### []()➕ **Add** [Section titled “ ➕ Add”](#--add) **Alias:** `a` ```bash npx @capgo/cli@latest channel add ``` ➕ Create a new channel for app distribution in Capgo Cloud to manage update delivery. **Example:** ```bash npx @capgo/cli@latest channel add production com.example.app --default ``` **Options:** | Param | Type | Description | | ---------------- | --------- | ---------------------------------------------------------------- | | **-d,** | `string` | Set the channel as default | | **—self-assign** | `boolean` | Allow device to self-assign to this channel | | **-a,** | `string` | API key to link to your account | | **—supa-host** | `string` | Custom Supabase host URL (for self-hosting or Capgo development) | | **—supa-anon** | `string` | Custom Supabase anon key (for self-hosting) | ### []()🗑️ **Delete** [Section titled “ 🗑️ Delete”](#-️-delete) **Alias:** `d` ```bash npx @capgo/cli@latest channel delete ``` 🗑️ Delete a channel from Capgo Cloud, optionally removing associated bundles to free up resources. **Example:** ```bash npx @capgo/cli@latest channel delete production com.example.app ``` **Options:** | Param | Type | Description | | ------------------------- | --------- | ---------------------------------------------------------------- | | **-a,** | `string` | API key to link to your account | | **—delete-bundle** | `boolean` | Delete the bundle associated with the channel | | **—success-if-not-found** | `boolean` | Success if the channel is not found | | **—supa-host** | `string` | Custom Supabase host URL (for self-hosting or Capgo development) | | **—supa-anon** | `string` | Custom Supabase anon key (for self-hosting) | ### []()📋 **List** [Section titled “ 📋 List”](#--list) **Alias:** `l` ```bash npx @capgo/cli@latest channel list ``` 📋 List all channels configured for an app in Capgo Cloud to review distribution settings. **Example:** ```bash npx @capgo/cli@latest channel list com.example.app ``` **Options:** | Param | Type | Description | | -------------- | -------- | ---------------------------------------------------------------- | | **-a,** | `string` | API key to link to your account | | **—supa-host** | `string` | Custom Supabase host URL (for self-hosting or Capgo development) | | **—supa-anon** | `string` | Custom Supabase anon key (for self-hosting) | ### []()📦 **CurrentBundle** [Section titled “ 📦 CurrentBundle”](#--currentbundle) ```bash npx @capgo/cli@latest channel currentBundle ``` 📦 Get the current bundle linked to a specific channel in Capgo Cloud for update tracking. **Example:** ```bash npx @capgo/cli@latest channel currentBundle production com.example.app ``` **Options:** | Param | Type | Description | | -------------- | --------- | ---------------------------------------------------------------- | | **-c,** | `string` | Channel to get the current bundle from | | **-a,** | `string` | API key to link to your account | | **—quiet** | `boolean` | Only print the bundle version | | **—supa-host** | `string` | Custom Supabase host URL (for self-hosting or Capgo development) | | **—supa-anon** | `string` | Custom Supabase anon key (for self-hosting) | ### []()⚙️ **Set** [Section titled “ ⚙️ Set”](#-️-set) **Alias:** `s` ```bash npx @capgo/cli@latest channel set ``` ⚙️ Configure settings for a channel, such as linking a bundle, setting update strategies (major, minor, metadata, patch, none), or device targeting (iOS, Android, dev, prod, emulator, device). One channel must be default. **Example:** ```bash npx @capgo/cli@latest channel set production com.example.app --bundle 1.0.0 --state default ``` **Options:** | Param | Type | Description | | -------------------------- | --------- | -------------------------------------------------------------------------- | | **-a,** | `string` | API key to link to your account | | **-b,** | `string` | Bundle version number of the file to set | | **-s,** | `string` | Set the state of the channel, default or normal | | **—latest-remote** | `boolean` | Get the latest bundle uploaded in capgo cloud and set it to the channel | | **—latest** | `boolean` | Get the latest version key in the package.json to set it to the channel | | **—downgrade** | `boolean` | Allow to downgrade to version under native one | | **—no-downgrade** | `boolean` | Disable downgrade to version under native one | | **—ios** | `boolean` | Allow sending update to iOS devices | | **—no-ios** | `boolean` | Disable sending update to iOS devices | | **—android** | `boolean` | Allow sending update to Android devices | | **—no-android** | `boolean` | Disable sending update to Android devices | | **—self-assign** | `boolean` | Allow device to self-assign to this channel | | **—no-self-assign** | `boolean` | Disable devices to self-assign to this channel | | **—disable-auto-update** | `string` | Block updates by type: major, minor, metadata, patch, or none (allows all) | | **—dev** | `boolean` | Allow sending update to development devices | | **—no-dev** | `boolean` | Disable sending update to development devices | | **—prod** | `boolean` | Allow sending update to production devices | | **—no-prod** | `boolean` | Disable sending update to production devices | | **—emulator** | `boolean` | Allow sending update to emulator devices | | **—no-emulator** | `boolean` | Disable sending update to emulator devices | | **—device** | `boolean` | Allow sending update to physical devices | | **—no-device** | `boolean` | Disable sending update to physical devices | | **—package-json** | `string` | Paths to package.json files for monorepos (comma-separated) | | **—ignore-metadata-check** | `boolean` | Ignore checking node\_modules compatibility if present in the bundle | | **—supa-host** | `string` | Custom Supabase host URL (for self-hosting or Capgo development) | | **—supa-anon** | `string` | Custom Supabase anon key (for self-hosting) | # 👨‍⚕️ doctor > 👨‍⚕️ Check if your Capgo app installation is up-to-date and gather information useful for bug reports. 👨‍⚕️ Check if your Capgo app installation is up-to-date and gather information useful for bug reports. ```bash npx @capgo/cli@latest doctor ``` This command helps diagnose issues with your setup. **Example:** ```bash npx @capgo/cli@latest doctor ``` ## []()Options [Section titled “ Options”](#-options) | Param | Type | Description | | ----------------- | -------- | ----------------------------------------------------------- | | **—package-json** | `string` | Paths to package.json files for monorepos (comma-separated) | # 🚀 init > 🚀 Initialize a new app in Capgo Cloud with step-by-step guidance. 🚀 Initialize a new app in Capgo Cloud with step-by-step guidance. **Alias:** `i` ```bash npx @capgo/cli@latest init ``` This includes adding code for updates, building, uploading your app, and verifying update functionality. Capgo bundles are web assets and can be fetched by anyone who knows the URL. Use encryption for banking, regulated, or other high-security apps. **Example:** ```bash npx @capgo/cli@latest init YOUR_API_KEY com.example.app ``` ## []()Options [Section titled “ Options”](#-options) | Param | Type | Description | | -------------- | -------- | ---------------------------------------------------------------- | | **-n,** | `string` | App name for display in Capgo Cloud | | **-i,** | `string` | App icon path for display in Capgo Cloud | | **—supa-host** | `string` | Custom Supabase host URL (for self-hosting or Capgo development) | | **—supa-anon** | `string` | Custom Supabase anon key (for self-hosting) | # 🔐 key > 🔐 Manage encryption keys for secure bundle distribution in Capgo Cloud, supporting end-to-end encryption with RSA and AES combination. 🔐 Manage encryption keys for secure bundle distribution in Capgo Cloud, supporting end-to-end encryption with RSA and AES combination. ### []()🔹 **Save** [Section titled “ 🔹 Save”](#--save) ```bash npx @capgo/cli@latest key save ``` 💾 Save the public key in the Capacitor config, useful for CI environments. Recommended not to commit the key for security. **Example:** ```bash npx @capgo/cli@latest key save --key ./path/to/key.pub ``` **Options:** | Param | Type | Description | | ------------- | -------- | ------------------------------------ | | **-f,** | `string` | Force generate a new one | | **—key** | `string` | Key path to save in Capacitor config | | **—key-data** | `string` | Key data to save in Capacitor config | ### []()🔨 **Create** [Section titled “ 🔨 Create”](#--create) ```bash npx @capgo/cli@latest key create ``` 🔨 Create RSA key pair for end-to-end encryption. Creates .capgo\_key\_v2 (private) and .capgo\_key\_v2.pub (public) in project root. Public key is saved to capacitor.config for mobile app decryption. NEVER commit the private key - store it securely! **Example:** ```bash npx @capgo/cli@latest key create ``` **Options:** | Param | Type | Description | | ------- | -------- | ------------------------ | | **-f,** | `string` | Force generate a new one | ### []()🗑️ **Delete\_old** [Section titled “ 🗑️ Delete\_old”](#-️-delete_old) ```bash npx @capgo/cli@latest key delete_old ``` 🧹 Delete the old encryption key from the Capacitor config to ensure only the current key is used. **Example:** ```bash npx @capgo/cli@latest key delete_old ``` # 🔑 login > 🔑 Save your Capgo API key to your machine or local folder for easier access to Capgo Cloud services. 🔑 Save your Capgo API key to your machine or local folder for easier access to Capgo Cloud services. **Alias:** `l` ```bash npx @capgo/cli@latest login ``` Use —apikey=\*\*\*\*\*\*\*\* in any command to override it. **Example:** ```bash npx @capgo/cli@latest login YOUR_API_KEY ``` ## []()Options [Section titled “ Options”](#-options) | Param | Type | Description | | -------------- | --------- | ---------------------------------------------------------------- | | **—local** | `boolean` | Only save in local folder, git ignored for security. | | **—supa-host** | `string` | Custom Supabase host URL (for self-hosting or Capgo development) | | **—supa-anon** | `string` | Custom Supabase anon key (for self-hosting) | # 🔹 organisation > [DEPRECATED] Use "organization" instead. This command will be removed in a future version. \[DEPRECATED] Use “organization” instead. This command will be removed in a future version. ### []()📋 **List** [Section titled “ 📋 List”](#--list) **Alias:** `l` ```bash npx @capgo/cli@latest organisation list ``` \[DEPRECATED] Use “organization list” instead. **Options:** | Param | Type | Description | | -------------- | -------- | ---------------------------------------------------------------- | | **-a,** | `string` | API key to link to your account | | **—supa-host** | `string` | Custom Supabase host URL (for self-hosting or Capgo development) | | **—supa-anon** | `string` | Custom Supabase anon key (for self-hosting) | ### []()➕ **Add** [Section titled “ ➕ Add”](#--add) **Alias:** `a` ```bash npx @capgo/cli@latest organisation add ``` \[DEPRECATED] Use “organization add” instead. **Options:** | Param | Type | Description | | -------------- | -------- | ---------------------------------------------------------------- | | **-n,** | `string` | Organization name | | **-e,** | `string` | Management email for the organization | | **-a,** | `string` | API key to link to your account | | **—supa-host** | `string` | Custom Supabase host URL (for self-hosting or Capgo development) | | **—supa-anon** | `string` | Custom Supabase anon key (for self-hosting) | ### []()⚙️ **Set** [Section titled “ ⚙️ Set”](#-️-set) **Alias:** `s` ```bash npx @capgo/cli@latest organisation set ``` \[DEPRECATED] Use “organization set” instead. **Options:** | Param | Type | Description | | --------------------------------- | --------- | -------------------------------------------------------------------------- | | **-n,** | `string` | Organization name | | **-e,** | `string` | Management email for the organization | | **—enforce-2fa** | `boolean` | Enable 2FA enforcement for all organization members | | **—no-enforce-2fa** | `boolean` | Disable 2FA enforcement for organization | | **—password-policy** | `boolean` | Enable password policy enforcement for organization | | **—no-password-policy** | `boolean` | Disable password policy enforcement | | **—min-length** | `string` | Minimum password length (6-128, default: 10) | | **—require-uppercase** | `boolean` | Require uppercase letter in password | | **—no-require-uppercase** | `boolean` | Do not require uppercase letter | | **—require-number** | `boolean` | Require number in password | | **—no-require-number** | `boolean` | Do not require number | | **—require-special** | `boolean` | Require special character in password | | **—no-require-special** | `boolean` | Do not require special character | | **—require-apikey-expiration** | `boolean` | Require all API keys to have an expiration date | | **—no-require-apikey-expiration** | `boolean` | Do not require API key expiration | | **—max-apikey-expiration-days** | `string` | Maximum days before API key expiration (1-365, null for no limit) | | **—enforce-hashed-api-keys** | `boolean` | Enforce hashed/secure API keys (key value stored as hash, shown only once) | | **—no-enforce-hashed-api-keys** | `boolean` | Allow plain-text API keys | | **-a,** | `string` | API key to link to your account | | **—supa-host** | `string` | Custom Supabase host URL (for self-hosting or Capgo development) | | **—supa-anon** | `string` | Custom Supabase anon key (for self-hosting) | ### []()🗑️ **Delete** [Section titled “ 🗑️ Delete”](#-️-delete) **Alias:** `d` ```bash npx @capgo/cli@latest organisation delete ``` \[DEPRECATED] Use “organization delete” instead. **Options:** | Param | Type | Description | | -------------- | -------- | ---------------------------------------------------------------- | | **-a,** | `string` | API key to link to your account | | **—supa-host** | `string` | Custom Supabase host URL (for self-hosting or Capgo development) | | **—supa-anon** | `string` | Custom Supabase anon key (for self-hosting) | # 🔹 organization > 🏢 Manage your organizations in Capgo Cloud for team collaboration and app management. 🏢 Manage your organizations in Capgo Cloud for team collaboration and app management. ### []()📋 **List** [Section titled “ 📋 List”](#--list) **Alias:** `l` ```bash npx @capgo/cli@latest organization list ``` 📋 List all organizations you have access to in Capgo Cloud. **Example:** ```bash npx @capgo/cli@latest organization list ``` **Options:** | Param | Type | Description | | -------------- | -------- | ---------------------------------------------------------------- | | **-a,** | `string` | API key to link to your account | | **—supa-host** | `string` | Custom Supabase host URL (for self-hosting or Capgo development) | | **—supa-anon** | `string` | Custom Supabase anon key (for self-hosting) | ### []()➕ **Add** [Section titled “ ➕ Add”](#--add) **Alias:** `a` ```bash npx @capgo/cli@latest organization add ``` ➕ Create a new organization in Capgo Cloud for team collaboration. **Example:** ```bash npx @capgo/cli@latest organization add --name "My Company" --email admin@mycompany.com ``` **Options:** | Param | Type | Description | | -------------- | -------- | ---------------------------------------------------------------- | | **-n,** | `string` | Organization name | | **-e,** | `string` | Management email for the organization | | **-a,** | `string` | API key to link to your account | | **—supa-host** | `string` | Custom Supabase host URL (for self-hosting or Capgo development) | | **—supa-anon** | `string` | Custom Supabase anon key (for self-hosting) | ### []()🔹 **Members** [Section titled “ 🔹 Members”](#--members) **Alias:** `m` ```bash npx @capgo/cli@latest organization members ``` 👥 List organization members and their 2FA status. Shows all members of an organization with their roles and whether they have 2FA enabled. Useful before enabling 2FA enforcement to see which members will be affected. > ℹ️ Viewing 2FA status requires super\_admin rights in the organization. **Example:** ```bash npx @capgo/cli@latest organization members ORG_ID ``` **Options:** | Param | Type | Description | | -------------- | -------- | ---------------------------------------------------------------- | | **-a,** | `string` | API key to link to your account | | **—supa-host** | `string` | Custom Supabase host URL (for self-hosting or Capgo development) | | **—supa-anon** | `string` | Custom Supabase anon key (for self-hosting) | ### []()⚙️ **Set** [Section titled “ ⚙️ Set”](#-️-set) **Alias:** `s` ```bash npx @capgo/cli@latest organization set ``` ⚙️ Update organization settings including name, email, security policies, and enforcement options. Security settings require super\_admin role. **Example:** ```bash npx @capgo/cli@latest organization set ORG_ID --name "New Name" ``` **Options:** | Param | Type | Description | | --------------------------------- | --------- | -------------------------------------------------------------------------- | | **-n,** | `string` | Organization name | | **-e,** | `string` | Management email for the organization | | **—enforce-2fa** | `boolean` | Enable 2FA enforcement for all organization members | | **—no-enforce-2fa** | `boolean` | Disable 2FA enforcement for organization | | **—password-policy** | `boolean` | Enable password policy enforcement for organization | | **—no-password-policy** | `boolean` | Disable password policy enforcement | | **—min-length** | `string` | Minimum password length (6-128, default: 10) | | **—require-uppercase** | `boolean` | Require uppercase letter in password | | **—no-require-uppercase** | `boolean` | Do not require uppercase letter | | **—require-number** | `boolean` | Require number in password | | **—no-require-number** | `boolean` | Do not require number | | **—require-special** | `boolean` | Require special character in password | | **—no-require-special** | `boolean` | Do not require special character | | **—require-apikey-expiration** | `boolean` | Require all API keys to have an expiration date | | **—no-require-apikey-expiration** | `boolean` | Do not require API key expiration | | **—max-apikey-expiration-days** | `string` | Maximum days before API key expiration (1-365, null for no limit) | | **—enforce-hashed-api-keys** | `boolean` | Enforce hashed/secure API keys (key value stored as hash, shown only once) | | **—no-enforce-hashed-api-keys** | `boolean` | Allow plain-text API keys | | **-a,** | `string` | API key to link to your account | | **—supa-host** | `string` | Custom Supabase host URL (for self-hosting or Capgo development) | | **—supa-anon** | `string` | Custom Supabase anon key (for self-hosting) | ### []()🗑️ **Delete** [Section titled “ 🗑️ Delete”](#-️-delete) **Alias:** `d` ```bash npx @capgo/cli@latest organization delete ``` 🗑️ Delete an organization from Capgo Cloud. This action cannot be undone. Only organization owners can delete organizations. **Example:** ```bash npx @capgo/cli@latest organization delete ORG_ID ``` **Options:** | Param | Type | Description | | -------------- | -------- | ---------------------------------------------------------------- | | **-a,** | `string` | API key to link to your account | | **—supa-host** | `string` | Custom Supabase host URL (for self-hosting or Capgo development) | | **—supa-anon** | `string` | Custom Supabase anon key (for self-hosting) | # 🔹 probe > 🔎 Probe the Capgo updates endpoint to check if an update is available for your app. 🔎 Probe the Capgo updates endpoint to check if an update is available for your app. ```bash npx @capgo/cli@latest probe ``` Sends a single request to the updates endpoint using your project’s capacitor config and reports whether an update would be delivered, or explains why not. **Example:** ```bash npx @capgo/cli@latest probe --platform ios ``` ## []()Options [Section titled “ Options”](#-options) | Param | Type | Description | | ------------- | -------- | --------------------------------- | | **—platform** | `string` | Platform to probe: ios or android | # 🔹 star > ⭐ Star a Capgo GitHub repository to support the project. ⭐ Star a Capgo GitHub repository to support the project. ```bash npx @capgo/cli@latest star ``` If you do not pass a repository name, this defaults to capacitor-updater in the Cap-go org. # 🔹 star-all > ⭐ Star all Capgo GitHub repositories with a small random delay between each request. ⭐ Star all Capgo GitHub repositories with a small random delay between each request. ```bash npx @capgo/cli@latest star-all ``` If you do not pass repositories, this defaults to all Cap-go repositories whose name starts with `capacitor-`. ## []()Options [Section titled “ Options”](#-options) | Param | Type | Description | | -------------------- | -------- | ---------------------------------------------------------------- | | **—min-delay-ms** | `string` | Minimum delay in ms between each star action (default: 20) | | **—max-delay-ms** | `string` | Maximum delay in ms between each star action (default: 180) | | **—max-concurrency** | `string` | Maximum number of star requests running in parallel (default: 4) | # Adding or Updating Plugins > Complete guide for contributors and agents on how to add new plugins or update existing plugins in the Capgo documentation. This guide explains how to add new Capacitor plugins to the Capgo website or update existing plugin documentation. This is useful for contributors, maintainers, and AI agents helping to maintain the documentation. ## Overview [Section titled “Overview”](#overview) When adding a new plugin to the Capgo ecosystem, you need to update several files and locations across the website to ensure the plugin appears correctly in all relevant places: 1. **Plugin List Configuration** - Add plugin metadata to the master list 2. **Plugin Index Page** - Add plugin to the categorized plugin listing page 3. **Sidebar Navigation** - Add plugin to the documentation sidebar 4. **Plugin Documentation** - Create overview and getting-started pages 5. **Plugin Tutorial** - Create a comprehensive tutorial ## File Locations [Section titled “File Locations”](#file-locations) ### Key Files to Update [Section titled “Key Files to Update”](#key-files-to-update) | File | Purpose | | ----------------------------------------------- | --------------------------------- | | `/src/config/plugins.ts` | Master plugin list with metadata | | `/src/content/docs/docs/plugins/index.mdx` | Plugin index page with categories | | `/astro.config.mjs` | Sidebar navigation configuration | | `/src/content/docs/docs/plugins/[plugin-name]/` | Plugin documentation directory | | `/src/content/plugins-tutorials/en/` | English tutorial files | ## Step-by-Step Guide [Section titled “Step-by-Step Guide”](#step-by-step-guide) 1. ### Add Plugin to Master List [Section titled “Add Plugin to Master List”](#add-plugin-to-master-list) Open `/src/config/plugins.ts` and add your plugin to the `actions` array: ```typescript // First, import an appropriate Heroicon import YourIconName from 'astro-heroicons/mini/IconName.astro' // Then add to the actions array { name: '@capgo/your-plugin-name', author: 'github.com/Cap-go', description: 'Brief description of what the plugin does', href: 'https://github.com/Cap-go/your-plugin-name/', title: 'Display Name', icon: YourIconName, } ``` **Available Icons**: Check `/node_modules/astro-heroicons/mini/` for available icons. 2. ### Add Plugin to Index Page [Section titled “Add Plugin to Index Page”](#add-plugin-to-index-page) Open `/src/content/docs/docs/plugins/index.mdx` and add your plugin under the appropriate category: ```mdx ``` **Categories**: * ⭐ Featured Plugins * 📱 Device & System Plugins * 🎥 Media & Camera Plugins * 🛠️ Utility Plugins * 🤖 AI & Advanced Media * 📍 Location & Background Services * 📞 Communication & Analytics * 🔐 Security & System * 📊 Android-Specific Features * 📥 Download & Navigation 3. ### Add to Sidebar Navigation [Section titled “Add to Sidebar Navigation”](#add-to-sidebar-navigation) Open `/astro.config.mjs` and add your plugin to the sidebar configuration (around line 540): ```javascript { label: 'Your Plugin Name', items: [ { label: 'Overview', link: '/docs/plugins/your-plugin-name/' }, { label: 'Getting started', link: '/docs/plugins/your-plugin-name/getting-started' }, ], collapsed: true, } ``` Plugins are listed alphabetically in the sidebar. 4. ### Create Plugin Documentation Directory [Section titled “Create Plugin Documentation Directory”](#create-plugin-documentation-directory) Create a new directory for your plugin documentation: ```bash mkdir -p /src/content/docs/docs/plugins/your-plugin-name/ ``` 5. ### Create Plugin Overview Page [Section titled “Create Plugin Overview Page”](#create-plugin-overview-page) Create `/src/content/docs/docs/plugins/your-plugin-name/index.mdx`: ```mdx --- title: "@capgo/your-plugin-name" description: Brief description of the plugin's purpose tableOfContents: false next: false prev: false sidebar: order: 1 label: "Introduction" hero: tagline: Detailed tagline explaining what the plugin does image: file: ~public/your-plugin-icon.svg actions: - text: Get started link: /docs/plugins/your-plugin-name/getting-started/ icon: right-arrow variant: primary - text: Github link: https://github.com/Cap-go/your-plugin-name/ icon: external variant: minimal --- import { Card, CardGrid } from '@astrojs/starlight/components'; Description of first key feature Description of second key feature Works on both iOS and Android 📱 Check the [Documentation](/docs/plugins/your-plugin-name/getting-started/) to master the plugin. ``` 6. ### Create Getting Started Guide [Section titled “Create Getting Started Guide”](#create-getting-started-guide) Create `/src/content/docs/docs/plugins/your-plugin-name/getting-started.mdx`: ```mdx --- title: Getting Started description: Learn how to install and use the plugin in your Capacitor app. sidebar: order: 2 --- import { Steps } from '@astrojs/starlight/components'; import { PackageManagers } from 'starlight-package-managers' 1. **Install the package** 2. **Sync with native projects** ## Configuration ### iOS Configuration [iOS-specific setup instructions] ### Android Configuration [Android-specific setup instructions] ## Usage [Basic usage examples] ## API Reference [Detailed API documentation] ## Complete Example [Full working example] ## Best Practices [Recommended practices and tips] ## Platform Notes [Platform-specific notes and limitations] ``` 7. ### Create Tutorial File [Section titled “Create Tutorial File”](#create-tutorial-file) Create `/src/content/plugins-tutorials/en/your-plugin-name.md`: ```markdown --- locale: en --- # Using @capgo/your-plugin-name Package The `@capgo/your-plugin-name` package [brief description]. In this tutorial, we will guide you through the installation, configuration, and usage of this package in your Ionic Capacitor app. ## Installation [Installation steps] ## Configuration [Configuration steps for iOS and Android] ## API Usage [Detailed API usage examples] ## Complete Example [Full working example] ## Best Practices [Tips and best practices] ## Troubleshooting [Common issues and solutions] ## Conclusion [Summary and links to additional resources] ``` ## Plugin Documentation Structure [Section titled “Plugin Documentation Structure”](#plugin-documentation-structure) ### Required Files [Section titled “Required Files”](#required-files) ```plaintext src/content/docs/docs/plugins/your-plugin-name/ ├── index.mdx # Overview page with hero and feature cards └── getting-started.mdx # Installation and usage guide src/content/plugins-tutorials/en/ └── your-plugin-name.md # Comprehensive tutorial ``` ### Optional Files [Section titled “Optional Files”](#optional-files) For complex plugins, you may add additional documentation pages: ```plaintext src/content/docs/docs/plugins/your-plugin-name/ ├── index.mdx ├── getting-started.mdx ├── api-reference.mdx # Detailed API documentation ├── examples.mdx # Additional examples ├── troubleshooting.mdx # Troubleshooting guide └── migrations.mdx # Migration guides ``` ## Content Guidelines [Section titled “Content Guidelines”](#content-guidelines) ### Writing Plugin Descriptions [Section titled “Writing Plugin Descriptions”](#writing-plugin-descriptions) * **Be Concise**: Keep descriptions under 100 characters * **Be Specific**: Explain what the plugin does, not what it is * **Use Action Words**: Start with verbs like “Control”, “Integrate”, “Enable” **Good Examples**: * “Control device flashlight and torch with simple on/off toggle” * “Integrate Crisp live chat and customer support into your app” * “Enable secure authentication using Face ID and Touch ID” **Bad Examples**: * “A plugin for flash” * “This is a Crisp plugin” * “Biometric plugin” ### Writing Documentation [Section titled “Writing Documentation”](#writing-documentation) 1. **Start with Installation**: Always begin with clear installation steps 2. **Provide Configuration**: Include platform-specific setup requirements 3. **Show Usage Examples**: Provide working code examples 4. **Include API Reference**: Document all methods and parameters 5. **Add Complete Examples**: Show real-world usage patterns 6. **List Best Practices**: Share tips for optimal usage 7. **Document Platform Differences**: Clarify iOS vs Android behavior 8. **Add Troubleshooting**: Address common issues ### Code Examples [Section titled “Code Examples”](#code-examples) * Use TypeScript for all code examples * Include imports at the top * Add comments explaining key steps * Show error handling * Demonstrate both basic and advanced usage ## Checklist [Section titled “Checklist”](#checklist) Use this checklist when adding a new plugin: * [ ] Added plugin to `/src/config/plugins.ts` * [ ] Selected appropriate icon from Heroicons * [ ] Added plugin to `/src/content/docs/docs/plugins/index.mdx` under correct category * [ ] Added sidebar entry in `/astro.config.mjs` * [ ] Created plugin documentation directory * [ ] Created `index.mdx` overview page * [ ] Created `getting-started.mdx` guide * [ ] Created tutorial in `/src/content/plugins-tutorials/en/` * [ ] Included installation instructions * [ ] Documented iOS configuration * [ ] Documented Android configuration * [ ] Provided usage examples * [ ] Added API reference * [ ] Included complete working example * [ ] Listed best practices * [ ] Added platform-specific notes * [ ] Tested all links work correctly ## Icon Reference [Section titled “Icon Reference”](#icon-reference) Common icons used for plugins (from `astro-heroicons/mini/`): | Icon | Use Case | | ------------------------ | ----------------------------------- | | `BoltIcon` | Flash, power, energy | | `CameraIcon` | Camera, photo, video | | `ChatBubbleLeftIcon` | Chat, messaging, communication | | `FingerPrintIcon` | Biometric, security, authentication | | `MapPinIcon` | Location, geolocation, maps | | `SpeakerWaveIcon` | Audio, sound, music | | `VideoCameraIcon` | Video, recording, streaming | | `CreditCardIcon` | Payments, purchases | | `PlayCircleIcon` | Media players, video players | | `SignalIcon` | Connectivity, network, beacon | | `RadioIcon` | Beacon, broadcast, wireless | | `ChatBubbleOvalLeftIcon` | Social media, WeChat | ## Updating Existing Plugins [Section titled “Updating Existing Plugins”](#updating-existing-plugins) When updating an existing plugin: 1. **Update version numbers** in documentation 2. **Add migration guides** if breaking changes exist 3. **Update API reference** with new methods 4. **Add new examples** for new features 5. **Update platform requirements** if changed 6. **Revise best practices** based on new features 7. **Keep tutorial current** with latest API ## Language Paths [Section titled “Language Paths”](#language-paths) Write and review plugin docs in English. Localized paths are generated by the site metadata and translated at the edge by the translation Worker. ## Testing Your Changes [Section titled “Testing Your Changes”](#testing-your-changes) After adding or updating plugin documentation: 1. **Build the site locally**: ```bash bun run build ``` 2. **Check for errors**: * Verify all links work * Ensure images load correctly * Confirm code examples are valid * Test navigation works 3. **Preview the site**: ```bash bun run dev ``` 4. **Verify your plugin appears**: * Check plugin listing page * Verify sidebar navigation * Test all documentation pages * Confirm tutorial page works ## Common Pitfalls [Section titled “Common Pitfalls”](#common-pitfalls) Caution **Avoid these common mistakes:** 1. **Forgetting to sync**: Always run `bunx cap sync` in examples 2. **Inconsistent naming**: Use the same plugin name everywhere 3. **Missing platform config**: Document both iOS and Android setup 4. **Broken links**: Use relative links and verify they work 5. **No error handling**: Always show try-catch in examples 6. **Missing imports**: Include all necessary imports in examples 7. **Unclear descriptions**: Be specific about what the plugin does ## Getting Help [Section titled “Getting Help”](#getting-help) If you need help adding or updating plugin documentation: * **Discord**: Join our [Discord community](https://discord.capgo.app) * **GitHub**: Open an issue on the [website repository](https://github.com/Cap-go/website) * **Email**: Contact the team at ## Examples [Section titled “Examples”](#examples) For reference, check these well-documented plugins: * **Updater**: `/src/content/docs/docs/plugins/updater/` (complex plugin with multiple pages) * **Flash**: `/src/content/docs/docs/plugins/flash/` (simple plugin, good starter example) * **Social Login**: `/src/content/docs/docs/plugins/social-login/` (plugin with sub-pages) ## Summary [Section titled “Summary”](#summary) Adding a plugin to the Capgo documentation involves: 1. Adding metadata to the master configuration 2. Adding the plugin to the categorized index page 3. Configuring sidebar navigation 4. Creating comprehensive documentation pages 5. Writing a detailed tutorial 6. Testing all changes locally By following this guide, you ensure that plugins are consistently documented and easily discoverable by users. # FAQ > Frequently asked questions about Capgo, how to solve the most common issue in Capgo or with the Updater, what is OTA and how to manage them If you have questions not answered here, please ask! Both filing an issue or asking on [Discord](https://discord.capgo.app) work. ### What is “code push”?[](https://capgo.app/docs/#what-is-code-push "Direct link to What is \"code push\"?") [Section titled “What is “code push”?”](#what-is-code-push) Code push, also referred to as “over-the-air updates” (OTA) is a cloud service enabling Capacitor developers to deploy updates to their apps in production. Capgo currently works on Android, iOS, and Electron. “Code Push” is a reference to the name of a deploy feature used by the React Native community from [Microsoft](https://appcenter.ms/) and [Expo](https://expo.dev/), neither of which support Capacitor. ### What is the difference between a bundle and a release?[](https://capgo.app/docs/faq/#what-is-the-difference-between-a-bundle-and-a-release "Direct link to What is the difference between a bundle and a release?") [Section titled “What is the difference between a bundle and a release?”](#what-is-the-difference-between-a-bundle-and-a-release) We use the term “release” to mean preparing a binary for the app stores. In order to later generate a bundle Capgo needs to know the exact binary that was shipped to the app stores. We use the term “bundle” to mean a patch that can be applied to a release to update it to new code. The `npx @capgo/cli@latest bundle upload` command is used to generate a bundle from your new local code which is then shipped to your users. ### What is the roadmap?[](https://capgo.app/docs/faq/#what-is-the-roadmap "Direct link to What is the roadmap?") [Section titled “What is the roadmap?”](#what-is-the-roadmap) Our project boards are also public and found at: [https://github.com/orgs/Cap-go/projects](https://github.com/orgs/Cap-go/projects/) Our team also operates in the public, so you can see what we’re working on at any time. We’re happy to answer any questions you have about our roadmap or priorities via Github issues or [Discord](https://discord.capgo.app). ### Can I use Capgo with my team?[](https://capgo.app/docs/faq/#can-i-use-capgo-with-my-team "Direct link to Can I use Capgo with my team?") [Section titled “Can I use Capgo with my team?”](#can-i-use-capgo-with-my-team) Yes! All plans support unlimited developers. We only limit app metrics (MAU, storage and bandwidth) to each organization. See [Teams](https://capgo.app/pricing/) for more information. ### Does Capgo store my source code?[](https://capgo.app/docs/faq/#does-capgo-store-my-source-code "Direct link to Does Capgo store my source code?") [Section titled “Does Capgo store my source code?”](#does-capgo-store-my-source-code) No. Capgo servers never see your source code. When you run `npx @capgo/cli@latest bundle upload`, Capgo stores a zip file of the minified/compiled code - the same code that a browser would receive, not your source code. For additional security, you have two options: * **End-to-End Encryption**: Encrypt your bundle before uploading to protect it in storage and transit and to prevent third parties from generating valid encrypted updates without your private key. This does not make shipped web assets impossible to reverse engineer because the public key is present in the distributed app. * **External URL Upload**: Store the bundle on your own server and only provide Capgo with the download link with the option `--external ` See also our privacy policy: [https://capgo.app/privacy](https://capgo.app/privacy/) ### Can I use Capgo from my CI system?[](https://capgo.app/docs/faq/#can-i-use-capgo-from-my-ci-system "Direct link to Can I use Capgo from my CI system?") [Section titled “Can I use Capgo from my CI system?”](#can-i-use-capgo-from-my-ci-system) Yes. Capgo is intended to be used from CI systems. We’ve published a guide for [Android and Github Actions](https://capgo.app/blog/automatic-capacitor-android-build-github-action/) and [iOS](https://capgo.app/blog/automatic-capacitor-ios-build-github-action/), and for [GitLab](https://capgo.app/blog/setup-ci-and-cd-in-gitlab/). Other CI systems should be similar. Please don’t hesitate to reach out over GitHub issues or Discord if you encounter any issues. ### How does this relate to Firebase Remote Config or Launch Darkly?[](https://capgo.app/docs/faq/#how-does-this-relate-to-firebase-remote-config-or-launch-darkly "Direct link to How does this relate to Firebase Remote Config or Launch Darkly?") [Section titled “How does this relate to Firebase Remote Config or Launch Darkly?”](#how-does-this-relate-to-firebase-remote-config-or-launch-darkly) Code push allows adding new code / replacing code on the device. Firebase Remote Config and Launch Darkly are both configuration systems. They allow you to change the configuration of your app without having to ship a new version. They are not intended to replace code. ### How big of a dependency footprint does this add?[](https://capgo.app/docs/faq/#how-big-of-a-dependency-footprint-does-this-add "Direct link to How big of a dependency footprint does this add?") [Section titled “How big of a dependency footprint does this add?”](#how-big-of-a-dependency-footprint-does-this-add) I haven’t measured recently, but I expect the code push library to add less than one megabyte to Capacitor apps. We know of ways we can make this smaller when that becomes a priority. If size is a blocker for you, please let us know! ### Does Capgo work on the iOS 18.4 Simulator?[](https://capgo.app/docs/faq/#does-capgo-work-on-the-ios-18-4-simulator "Direct link to Does Capgo work on the iOS 18.4 Simulator?") [Section titled “Does Capgo work on the iOS 18.4 Simulator?”](#does-capgo-work-on-the-ios-184-simulator) No. Due to an upstream issue affecting the iOS 18.4 Simulator, Capgo does not run reliably there. Please test on a real device or use a different iOS simulator version. See details in the React Native issue: [facebook/react-native#50510](https://github.com/facebook/react-native/issues/50510) ### Does code push work with large applications?[](https://capgo.app/docs/faq/#does-code-push-work-with-large-applications "Direct link to Does code push work with large applications?") [Section titled “Does code push work with large applications?”](#does-code-push-work-with-large-applications) Yes. There is no limit on the size of the application that can be updated with code push. As noted [below](https://capgo.app/docs/faq/#what-types-of-changes-does-capgo-code-push-support), Capgo can change any JS code in your application regardless of size. To note: A bigger size make it harder for users to download updates. We recommend keeping your app as small as possible. ### What can I use Capgo code push for?[](https://capgo.app/docs/faq/#what-can-i-use-capgo-code-push-for "Direct link to What can I use Capgo code push for?") [Section titled “What can I use Capgo code push for?”](#what-can-i-use-capgo-code-push-for) We’ve seen a variety of uses, including: * Emergency fixes to production apps. * Shipping bug fixes to users on older versions of your app. * Shipping constantly (e.g. every hour). Note that most app stores prohibit shipping code that changes the behavior of the app in a significant way. Please see [below](https://capgo.app/docs/faq/#how-does-this-relate-to-the-appplay-store-review-process-or-policies) for more information. ### What counts as a “MAU” for Capgo?[](https://capgo.app/docs/faq/#what-counts-as-a-mau-for-capgo "Direct link to What counts as a \"MAU\" for Capgo?") [Section titled “What counts as a “MAU” for Capgo?”](#what-counts-as-a-mau-for-capgo) A MAU is a “Monthly Active User”. In Capgo’s context, this actually refers to a Monthly Active Device. We count a MAU as any device that has contacted our servers in the last 30 days. We do not count devices that have not contacted our servers in the last 30 days. **Important**: Starting from plugin version **v5.10.0**, **v6.25.0** and **v7.25.0**, the deviceID now persists across app reinstalls. Before these versions, each app reinstall would generate a new deviceID and count as a new MAU. With the current versions: * DeviceID persists across app reinstalls (stored securely in Keychain on iOS and EncryptedSharedPreferences on Android) * Updating the app does not create a new Device ID * During development, if you’re using an older plugin version (< v5.10.0 / v6.25.0 / v7.25.0), each reinstall still creates a new MAU Note: TestFlight downloads and channel switches in Android may still generate new device registrations depending on your configuration. > We recommend after first setup, to disable dev devices and emulators to reduce the amount of duplicated devices. ### What can’t we use Capgo code push for?[](https://capgo.app/docs/faq/#what-cant-we-use-capgo-code-push-for "Direct link to What can't we use Capgo code push for?") [Section titled “What can’t we use Capgo code push for?”](#what-cant-we-use-capgo-code-push-for) As above, Capgo should not be used to violate app store polices. Please see [below](https://capgo.app/docs/faq/#does-capgo-comply-with-play-store-guidelines) for more information. Also Capgo does not support changing native code (e.g. Java/Kotlin on Android or Objective-C/Swift on iOS). The tool will warn you during an attempted update if you have changed native code. ### Can I update capacitor.config.ts changes via Capgo?[](https://capgo.app/docs/faq/#can-i-update-capacitorconfigts-changes-via-capgo "Direct link to Can I update capacitor.config.ts changes via Capgo?") [Section titled “Can I update capacitor.config.ts changes via Capgo?”](#can-i-update-capacitorconfigts-changes-via-capgo) No. Changes to `capacitor.config.ts` cannot be sent through Capgo live updates. The Capacitor configuration file is read at native build time and compiled into the native app binary. This means any changes to `capacitor.config.ts` (such as plugin configurations, app ID, server settings, or native plugin options) require a new native release through the App Store or Google Play. Capgo can only update web assets (HTML, CSS, JavaScript) that are loaded at runtime. If you need to change your Capacitor configuration, you must: 1. Update `capacitor.config.ts` locally 2. Rebuild your native app (`npx cap sync` followed by a native build) 3. Submit the new binary to the app stores ### Does Capgo submit to the stores for me?[](https://capgo.app/docs/faq/#does-capgo-submit-to-the-stores-for-me "Direct link to Does Capgo submit to the stores for me?") [Section titled “Does Capgo submit to the stores for me?”](#does-capgo-submit-to-the-stores-for-me) Capgo does not currently support submitting to the app stores on your behalf. We have plans to add this in the future, but for now you will need to continue to use your existing processes to submit to the app stores. You can use our [CI guide Android](https://capgo.app/blog/automatic-capacitor-android-build-github-action/) to automate this process and [CI guide iOS](https://capgo.app/blog/automatic-capacitor-ios-build-github-action/). ### What does Capgo store on disk and where?[](https://capgo.app/docs/faq/#what-does-capgo-store-on-disk-and-where "Direct link to What does Capgo store on disk and where?") [Section titled “What does Capgo store on disk and where?”](#what-does-capgo-store-on-disk-and-where) The Capgo updater (included in your application when you build your app) caches the latest downloaded bundle in the only directory that capacitor allow to load code. On Android, this is located in `/data/user/0/com.example.app/code_cache/capgo_updater` although the base of that path is provided by the Android system and can change dynamically at runtime. On iOS devices, data is stored under `Library/Application Support/capgo`. The Capgo command line tools (e.g. `npx @capgo/cli@latest bundle upload`) are installed on disk in npm caches, your logins are stored in your home directory in `~/.capgo`. ### How does this relate to Capacitor Hot Reload?[](https://capgo.app/docs/faq/#how-does-this-relate-to-capacitor-hot-reload "Direct link to How does this relate to Capacitor Hot Reload?") [Section titled “How does this relate to Capacitor Hot Reload?”](#how-does-this-relate-to-capacitor-hot-reload) Capacitor’s Hot reload is a development-time-only feature. Code push is for production. Hot reload is a feature of Capacitor that allows you to change code on the device during development. It requires building the Capacitor app with a proxy to connect to your local machine. Code push is a feature that allows you to change code on the device in production. We will use a variety of different techniques to make this possible depending on the platform. ### What types of changes does Capgo code push support?[](https://capgo.app/docs/faq/#what-types-of-changes-does-capgo-code-push-support "Direct link to What types of changes does Capgo code push support?") [Section titled “What types of changes does Capgo code push support?”](#what-types-of-changes-does-capgo-code-push-support) Capgo can change any JS code in your application. This includes app code and generated code. You can also update dependencies in `package.json` as long as they don’t require native code changes. We do not have plans to support changing native code (e.g. Java/Kotlin on Android or Objective-C/Swift on iOS), and the tool will warn you if it detects that you have changed native code as it will not be included in the bundle. ### Does this support Web?[](https://capgo.app/docs/faq/#does-this-support-web "Direct link to Does this support Web?") [Section titled “Does this support Web?”](#does-this-support-web) Code push isn’t needed for web as the web already works this way. When a user opens a web app it downloads the latest version from the server if needed. If you have a use case for code push with web, we’d love to know! ### Will this work on iOS, Android, Mac, Windows, Linux, etc?[](https://capgo.app/docs/faq/#will-this-work-on-ios-android-mac-windows-linux-etc "Direct link to Will this work on iOS, Android, Mac, Windows, Linux, etc?") [Section titled “Will this work on iOS, Android, Mac, Windows, Linux, etc?”](#will-this-work-on-ios-android-mac-windows-linux-etc) Yes. So far we’ve focused on Android, iOS, and Electron support, and code push is production-ready on all three. ### What OS versions does Capgo support?[](https://capgo.app/docs/faq/#what-os-versions-does-capgo-support "Direct link to What OS versions does Capgo support?") [Section titled “What OS versions does Capgo support?”](#what-os-versions-does-capgo-support) Capgo supports the same versions of Android that Capacitor supports. Capacitor currently supports Android API level 22+ and iOS 13.0+: [https://capacitorjs.com/docs/main/reference/support-policy](https://capacitorjs.com/docs/main/reference/support-policy/) ### What versions of Capacitor does Capgo support?[](https://capgo.app/docs/faq/#what-versions-of-capacitor-does-capgo-support "Direct link to What versions of Capacitor does Capgo support?") [Section titled “What versions of Capacitor does Capgo support?”](#what-versions-of-capacitor-does-capgo-support) Capgo currently supports only recent stable releases of Capacitor. We could support older versions of Capacitor as well, we just haven’t built out the infrastructure necessary to maintain such over time. We intend to support more versions of Capacitor in the future, including any version for our enterprise customers. [https://github.com/Cap-go/capgo/issues/1100](https://github.com/Cap-go/capgo/issues/1100/) Capgo tracks Capacitor stable and generally updates within a few hours of any stable release. Our system for doing these updates is automated takes a few minutes to run. We then do an extra manual verification step before publishing to our servers. ### How does this relate to the App/Play Store review process or policies?[](https://capgo.app/docs/faq/#how-does-this-relate-to-the-appplay-store-review-process-or-policies "Direct link to How does this relate to the App/Play Store review process or policies?") [Section titled “How does this relate to the App/Play Store review process or policies?”](#how-does-this-relate-to-the-appplay-store-review-process-or-policies) Developers are bound by their agreements with store providers when they choose to use those stores. Code push is designed to allow developers to update their apps and still comply with store policies on iOS, Android, and Electron delivery channels. Similar to the variety of commercial products available to do so with React Native (e.g. [Microsoft](https://appcenter.ms/), [Expo](https://expo.dev/)). Microsoft also publishes a guide on how their solution complies with the app stores: [https://github.com/microsoft/react-native-code-push#store-guideline-compliance](https://github.com/microsoft/react-native-code-push/#store-guideline-compliance) Code push is a widely used technique throughout the app stores. All of the large apps I’m aware of use code push. The major policy to be aware of is not to change the behavior of the app in a significant way. Please see [below](https://capgo.app/docs/faq/#does-capgo-comply-with-play-store-guidelines) for more information. ### Does Capgo comply with Play Store guidelines?[](https://capgo.app/docs/faq/#does-capgo-comply-with-play-store-guidelines "Direct link to Does Capgo comply with Play Store guidelines?") [Section titled “Does Capgo comply with Play Store guidelines?”](#does-capgo-comply-with-play-store-guidelines) Yes. The Play Store offers two restrictions relating to update tools. 1. Updates must use an interpreter or virtual machine (Capgo uses JavaScript in a WebView). [https://support.google.com/googleplay/android-developer/answer/9888379?hl=en](https://support.google.com/googleplay/android-developer/answer/9888379/?hl=en) ```plaintext An app distributed via Google Play may not modify, replace, or update itself using any method other than Google Play's update mechanism. Likewise, an app may not download executable code (such as dex, JAR, .so files) from a source other than Google Play. *This restriction does not apply to code that runs in a virtual machine or an interpreter* where either provides indirect access to Android APIs (such as JavaScript in a webview or browser). Apps or third-party code, like SDKs, with interpreted languages (JavaScript, Python, Lua, etc.) loaded at run time (for example, not packaged with the app) must not allow potential violations of Google Play policies. ``` 2. Changes to the app must not be deceptive (e.g. changing the purpose of the app via update). [https://support.google.com/googleplay/android-developer/answer/9888077](https://support.google.com/googleplay/android-developer/answer/9888077/) Please be clear with your users about what you are providing with your application and do not violate their expectations with significant behavioral changes through the use of Capgo. Capgo is designed to be compatible with the Play Store guidelines. However Capgo is a tool, and as with any tool, can be abused. Deliberately abusing Capgo to violate Play Store guidelines is in violation of the Capgo [Terms of Service](https://capgo.app/tos/) and can result in termination of your account. Finally, code push services are widely used in the industry (all of the large apps I’m aware of use them) and there are multiple other code push services publicly available (e.g. expo.dev & appcenter.ms). This is a well trodden path. Microsoft also publishes a guide on how their react native “codepush” library complies with the app stores: [https://github.com/microsoft/react-native-code-push#store-guideline-compliance](https://github.com/microsoft/react-native-code-push/#store-guideline-compliance) ### Does Capgo comply with App Store guidelines?[](https://capgo.app/docs/faq/#does-capgo-comply-with-app-store-guidelines "Direct link to Does Capgo comply with App Store guidelines?") [Section titled “Does Capgo comply with App Store guidelines?”](#does-capgo-comply-with-app-store-guidelines) Yes. Similar to the Play Store, the App Store offers both technical and policy restrictions. ```plaintext 3.2.2 ... interpreted code may be downloaded to an Application but only so long as such code: (a) does not change the primary purpose of the Application by providing features or functionality that are inconsistent with the intended and advertised purpose of the Application as submitted to the App Store, (b) does not create a store or storefront for other code or applications, and (c) does not bypass signing, sandbox, or other security features of the OS. ``` Capgo uses JavaScript in a WebView to comply with the interpreter-only restriction for updates on iOS. So long as your application is not engaging in deceptive behavior via updates (e.g. changing the purpose of the app via update), updating via Capgo (or any other code push solution) is standard industry practice and compliant with App Store guidelines. Deliberately abusing Capgo to violate App Store guidelines is in violation of the Capgo [Terms of Service](https://capgo.app/tos/) and can result in termination of your account. Microsoft also publishes a guide on how their react native “codepush” library complies with the app stores: [https://github.com/microsoft/react-native-code-push#store-guideline-compliance](https://github.com/microsoft/react-native-code-push/#store-guideline-compliance) ### Can I use Capgo in my country?[](https://capgo.app/docs/faq/#can-i-use-capgo-in-my-country "Direct link to Can I use Capgo in my country?") [Section titled “Can I use Capgo in my country?”](#can-i-use-capgo-in-my-country) We have not attempted to restrict access to Capgo from any country. We recognize that some countries have restrictions on what urls can be accessed from within the country. Capgo currently uses Cloudflare Cloud for hosting, including R2 Storage and Cloudflare workers. The following URLs are used by Capgo: * [https://api.capgo.app](https://api.capgo.app/) — used by the `npx @capgo/cli` command line tools to interact with the Capgo servers as well as the Capgo updater on users’ devices to check for updates. * [https://\*.r2.cloudflarestorage.com](https://*.r2.cloudflarestorage.com/) — used by the `npx @capgo/cli` command line tool to upload and download bundle If all of those URLs are accessible from your country, then Capgo should work. If your region requires blocking access to any of those URLs, please let us know and we can work with you to find a solution. Proxy servers are one option. ### Can I self-host Capgo?[](https://capgo.app/docs/faq/#can-i-self-host-capgo "Direct link to Can I self-host Capgo?") [Section titled “Can I self-host Capgo?”](#can-i-self-host-capgo) Yes, you can self-host Capgo. The guide is not yet written, but the code is open source and available at [https://github.com/cap-go/capgo](https://github.com/cap-go/capgo/) ### Does code push require the internet to work?[](https://capgo.app/docs/faq/#does-code-push-require-the-internet-to-work "Direct link to Does code push require the internet to work?") [Section titled “Does code push require the internet to work?”](#does-code-push-require-the-internet-to-work) Yes. One could imagine running a server to distribute the updates separately from the general internet, but some form of network connectivity is required to transport updates to the devices. ### How is Capgo affected by lack of network connectivity?[](https://capgo.app/docs/faq/#how-is-capgo-affected-by-lack-of-network-connectivity "Direct link to How is Capgo affected by lack of network connectivity?") [Section titled “How is Capgo affected by lack of network connectivity?”](#how-is-capgo-affected-by-lack-of-network-connectivity) Capgo updater (included in your application when you build your app with Capgo) is designed to be resilient to network connectivity issues. In the default update behavior, when the application launches it alerts the Capgo updater, which spawns a separate thread to make a network request to Capgo’s servers and ask for an update. We intentionally use a separate thread to avoid affecting blocking anything else the application might be doing. If the network request fails or times out, the updater will simply try to check again next time the application launches. Capgo command line tools (e.g. `npx @capgo/cli@latest bundle upload`) require network connectivity to function. If you are using Capgo to distribute your app, you should ensure that your CI system has network connectivity. ### What happens if a user doesn’t update for a long time and misses an update?[](https://capgo.app/docs/faq/#what-happens-if-a-user-doesnt-update-for-a-long-time-and-misses-an-update "Direct link to What happens if a user doesn't update for a long time and misses an update?") [Section titled “What happens if a user doesn’t update for a long time and misses an update?”](#what-happens-if-a-user-doesnt-update-for-a-long-time-and-misses-an-update) Our implementation always sends an update specifically tailored for the device that is requesting it updating the requestor always to the latest version available. Thus if a user doesn’t update for a while they will “miss” intermediate updates. The update server could be changed to support responding with either the next incremental version or the latest version depending on your application’s needs. Please let us know if alternative update behaviors are important to you. ### How does Capgo relate to Capacitor?[](https://capgo.app/docs/faq/#how-does-capgo-relate-to-capacitor "Direct link to How does Capgo relate to Capacitor?") [Section titled “How does Capgo relate to Capacitor?”](#how-does-capgo-relate-to-capacitor) Capgo is a plugin for Capacitor that adds code push. Capgo is not a replacement for Capacitor. You can continue to use the Capacitor tooling you already know and love. We track the latest stable release of Capacitor and update our code push plugin to work with it. ### When do updates happen?[](https://capgo.app/docs/faq/#when-do-updates-happen "Direct link to When do updates happen?") [Section titled “When do updates happen?”](#when-do-updates-happen) By default, the Capgo updater checks for updates on app startup. It runs on a background thread and does not block the UI thread. Any updates will be installed while the user is using the app and will be applied the next time the app is restarted. It is also possible to run the Capgo updater manually using the `@capgo/capacitor-updater` package, through which it is possible to trigger updates at any time, including via a push notification. The Capgo updater is designed such that when the network is not available, or the server is down or otherwise unreachable, the app will continue to run as normal. Should you ever choose to delete an update from our servers, all your clients will continue to run as normal. We have added the ability to rollback patches. The simplest thing is to simply attach a previous bundle to your channel to undo. ### Do I need to keep my app\_id secret?[](https://capgo.app/docs/faq/#do-i-need-to-keep-my-app_id-secret "Direct link to Do I need to keep my app_id secret?") [Section titled “Do I need to keep my app\_id secret?”](#do-i-need-to-keep-my-app_id-secret) No. The `app_id` is included in your app and is safe to be public. You can check it into version control (even publicly) and not worry about someone else accessing it. Someone who has your `app_id` can fetch the latest version of your app from Capgo servers, but they cannot push updates to your app or access any other aspect of your Capgo account. ### What information is sent to Capgo servers?[](https://capgo.app/docs/faq/#what-information-is-sent-to-capgo-servers "Direct link to What information is sent to Capgo servers?") [Section titled “What information is sent to Capgo servers?”](#what-information-is-sent-to-capgo-servers) Although Capgo connects to the network, it does not send any personally identifiable information. Including Capgo should not affect your declarations for the Play Store or App Store. Requests sent from the app to Capgo servers include: * app\_id (specified `capacitor.config.json`) * channel (optional in `capacitor.config.json`) * release\_version (versionName from AndroidManifest.xml or CFBundleShortVersionString from Info.plist or `capacitor.config.json` if set in [`CapacitorUpdater.version`](/docs/plugins/updater/settings/#version) ) * version\_number (generated as part of `npx @capgo/cli@latest bundle upload`) * os\_version (e.g. ‘11.2.1’) * platform (e.g. ‘android’, needed to send down the right patch) That’s it. The code for this is in `updater/library/src/network.rs` * device\_id (generated on the device on first run, used to de-duplicate per-device installs and allow us to charge based on users installed to (e.g. monthly active users), rather than total patches or total patch installs) * custom\_id ( optional, set at runtime by the developer, used for you to link a device to a user in your system) ### What platforms does Capgo support?[](https://capgo.app/docs/faq/#what-platforms-does-capgo-support "Direct link to What platforms does Capgo support?") [Section titled “What platforms does Capgo support?”](#what-platforms-does-capgo-support) Currently, Capgo supports Android, iOS, and Electron. All are production-ready. Use of Capgo for iOS, Android, or Electron can be independent decisions. You can set your channel strategy for Android and an ipa built to the App Store, or Electron channels, as needed. Capgo can (relatively easily) be made to support desktop or embedded targets. If those are important to you, please let us know. ### How does Capgo interact with Play Testing Tracks or Apple TestFlight?[](https://capgo.app/docs/faq/#how-does-capgo-interact-with-play-testing-tracks-or-apple-testflight "Direct link to How does Capgo interact with Play Testing Tracks or Apple TestFlight?") [Section titled “How does Capgo interact with Play Testing Tracks or Apple TestFlight?”](#how-does-capgo-interact-with-play-testing-tracks-or-apple-testflight) Each of the app stores have separate mechanisms for distributing apps to limited groups of users (e.g. “internal testing”, “closed beta”, etc.). These are all mechanisms for segmenting your users into groups and distributing specific versions of your apps to each. Unfortunately, these not all of these mechanisms allow 3rd parties to detect when apps are installed in any specific Test Track or via TestFlight. Thus, we do not have reliable visibility into composition of these groups, and cannot reliably gate access to Capgo patches based on these groups. [https://stackoverflow.com/questions/53291007/can-an-android-application-identify-the-test-track-within-google-play](https://stackoverflow.com/questions/53291007/can-an-android-application-identify-the-test-track-within-google-play/) [https://stackoverflow.com/questions/26081543/how-to-tell-at-runtime-whether-an-ios-app-is-running-through-a-testflight-beta-i](https://stackoverflow.com/questions/26081543/how-to-tell-at-runtime-whether-an-ios-app-is-running-through-a-testflight-beta-i/) If you’d like to segment availability of Capgo bundle, there are 4 potential options: 1. Use separate channel for each group. This is the most straightforward approach, but requires you to manage multiple channels. You may already have a dev channels and prod channels with different availability. You can thus update your dev channels, verify it and then separately update your prod channels. We recommend using branches / tags in your version control to help keep track of the sources associated with each release. 2. Track your own set of opt-in users, disable automatic updates, and trigger updates only for certain users via the `@capgo/capacitor-updater` package. This works today, but requires you to manage your own opt-in list. 3. Capgo allow creare its own opt-in mechanism on a per-device basis (similar to Test Tracks or TestFlight, just platform agnostic). This allow your QA team to opt-in to bundle before they’re promoted to the general public. 4. Capgo have percentage based rollouts. This does not let you choose which devices to send to, but can help you roll out incrementally and roll-back on sight of any problems. ## Billing[](https://capgo.app/docs/faq/#billing "Direct link to Billing") [Section titled “Billing”](#billing) ### How do I upgrade or downgrade my plan?[](https://capgo.app/docs/faq/#how-do-i-upgrade-or-downgrade-my-plan "Direct link to How do I upgrade or downgrade my plan?") [Section titled “How do I upgrade or downgrade my plan?”](#how-do-i-upgrade-or-downgrade-my-plan) You can upgrade or downgrade your plan at any time in your dashboard: [https://console.capgo.app/settings/organization/plans](https://console.capgo.app/settings/organization/plans/) ### When does my billing period reset?[](https://capgo.app/docs/faq/#when-does-my-billing-period-reset "Direct link to When does my billing period reset?") [Section titled “When does my billing period reset?”](#when-does-my-billing-period-reset) Billing periods are reset automatically every month on the month you first subscribed to Capgo. For example, if you subscribed on the 15th of the month, your billing period will reset on the 15th of every month. ### How do I cancel my subscription?[](https://capgo.app/docs/faq/#how-do-i-cancel-my-subscription "Direct link to How do I cancel my subscription?") [Section titled “How do I cancel my subscription?”](#how-do-i-cancel-my-subscription) You can cancel your subscription at any time in your dashboard: [https://console.capgo.app/settings/organization/plans](https://console.capgo.app/settings/organization/plans/) ### Can I pay for a year in advance?[](https://capgo.app/docs/faq/#can-i-pay-for-a-year-in-advance "Direct link to Can I pay for a year in advance?") [Section titled “Can I pay for a year in advance?”](#can-i-pay-for-a-year-in-advance) Yes you can can at any time in your dashboard: [https://console.capgo.app/settings/organization/plans](https://console.capgo.app/settings/organization/plans/) ### Stats and analytics[](https://capgo.app/docs/faq/#stats-and-analytics "Direct link to Stats and analytics") [Section titled “Stats and analytics”](#stats-and-analytics) The stats in your dashboard are updated every midnight UTC. The stats are calculated based on the number of [MAU](https://capgo.app/docs/faq/#what-is-the-difference-between-a-bundle-and-a-release "Direct link to What is the difference between a bundle and a release?") that have been installed on your devices. ## How device ID is generated[](https://capgo.app/docs/faq/#how-device-id-is-generated "Direct link to How device ID is generated") [Section titled “How device ID is generated”](#how-device-id-is-generated) The device ID is generated on the device on first run, and is used to de-duplicate per-device installs and allow us to charge based on users installed to (e.g. monthly active users), rather than total patches or total patch installs. MAU is a better solution than number of installs to price Capgo, as it is more accurate and reflects the actual cost of Capgo per device. **DeviceID Persistence (Updated in v6.25.0 and v7.25.0)**: * **Current behavior**: The deviceID now persists across app reinstalls. It is stored securely in the device’s Keychain (iOS) or EncryptedSharedPreferences (Android), allowing us to track the same device even after uninstall/reinstall. * **Previous behavior** (before v6.25.0/v7.25.0): For privacy reasons related to Apple and Google store policies, the deviceID was reset on each app reinstall, making it impossible to track the same device across reinstalls. The privacy rules are enforced by Apple and Google, and Capgo’s implementation complies with their best practices for device identification. Device ID will not be listed in your device list until they get their first patch installed. ## Why my device number is different than my MAU?[](https://capgo.app/docs/faq/#why-my-device-number-is-different-than-my-mau "Direct link to Why my device number is different than my MAU?") [Section titled “Why my device number is different than my MAU?”](#why-my-device-number-is-different-than-my-mau) Currently, the device list is not updated as often as the MAU. The device list is updated only when a device installs an update. While the MAU is updated at every app launch. This is a current limitation of the platform. Our Analytics platform do not support raw updates so we use conventional database for Devices list. To limit the number of database queries, we do update row only on app update. This limitation will be removed in the future. ## How to have different update by platform?[](https://capgo.app/docs/faq/#how-to-have-different-update-by-platform "Direct link to How to have different update by platform?") [Section titled “How to have different update by platform?”](#how-to-have-different-update-by-platform) You can create a channel for each platform. and disable platform specific updates in each channel. On ios channel disable android updates and on android channel disable ios updates. Then upload a bundle to each channel to have different update for each platform. If you need to have the same update for both platform, you can link one bundle to multiple channels. No need to duplicate the bundle. # Tech support for Capgo > How to get tech support for Capgo and our updater, please follow this guide to get help when the doc and our articles are not enough ## Support by discord [Section titled “Support by discord”](#support-by-discord) Capgo has an official [discord server](https://discord.capgo.app). Getting tech support there is likely one of the fastest ways to get a response. Here is a crash course: Step 1 - go to the `questions` channel ![Ask on discord](/discord-questions.webp) Step 2 - create your thread ![Create a question on discord](/discord-newquestion.webp) Step 3 - Describe your problem and select the relevant tags ![Create a post on discord](/discord-new-post.webp) Step 4 - Share your secure account id (optional) This will allow the capgo staff to take a look at your account. Sharing this id is safe, as it was designed to be shared publicly. To share this, please go to [capgo’s settings](https://console.capgo.app/dashboard/settings/account/). There please click on `copy account id`. ![Share your id without leaking your info](/share-secure-id.webp) This will copy the secure account id to the clipboard. Please include that in your discord post. ## Support by email [Section titled “Support by email”](#support-by-email) This is the slowest way to get support. Please use the discord server first. If you need to contact us by email, please send an email to . # Add an App > Add an app to your Capgo account, and install the plugin in your app ## Requirements [Section titled “Requirements”](#requirements) Before getting started with Capgo, make sure you have: * A Capacitor app installed and configured. [Learn how to set up Capacitor](https://capacitorjs.com/docs/getting-started/) * Node.js 20 or later installed * One of the following development environments: * **macOS** with Xcode (for iOS development) and/or Android Studio (for Android development) * **Linux** with Android Studio (for Android development) * **Windows** with Android Studio (for Android development) ## Introduction to Capgo [Section titled “Introduction to Capgo”](#introduction-to-capgo) [Capgo in 15 min](https://www.youtube-nocookie.com/embed/NzXXKoyhTIo) ## Live updates are 3 step away [Section titled “Live updates are 3 step away”](#live-updates-are-3-step-away) ### Guided setup [Section titled “Guided setup”](#guided-setup) 1. Create your account at . ![signup screenshot](/signup.webp "signup screenshot") 2. Use the Init commands to get started ```bash npx @capgo/cli@latest init [APIKEY] ``` You will be presented with a series of questions. Provide the necessary answers to complete the automated setup. 3. Deploy a live update Tip By following these steps, you’ll be up and running in no time. If you need any further assistance during the process, our support team is [here to help](https://support.capgo.app). Happy onboarding! [Detailed Onboarding Guide ](/docs/getting-started/onboarding/)See the complete step-by-step guide for the CLI onboarding process [Deploy a live update ](/docs/getting-started/deploy/)Learn how to deploy a live update to your app ### Manual setup [Section titled “Manual setup”](#manual-setup) In case the init command doesn’t work for you, you can manually add an app. 1. Connect the CLI to your account: ```bash npx @capgo/cli@latest login [APIKEY] ``` 2. Add the app to your account with this command: ```bash npx @capgo/cli@latest app add [APP_NAME] ``` 3. Install the plugin in your app: ```bash npm i @capgo/capacitor-updater ``` 4. Configure the plugin in your `capacitor.config` ```json { "plugins": { CapacitorUpdater: { "appId": "Your appID", "autoUpdate": true, "version": "1.0.0" } } } ``` [See all available options](/docs/plugins/updater/settings/). This information will be inferred if not provided. 5. Call the init method as early as possible in your app: ```typescript import { CapacitorUpdater } from '@capgo/capacitor-updater'; CapacitorUpdater.notifyAppReady(); ``` 6. Deploy a live update Installing for older Capacitor versions The command above (step 3) installs the latest version (v8.x) for Capacitor 8. For older Capacitor versions, use the appropriate npm tag: ```bash # Capacitor 7 npm i @capgo/capacitor-updater@lts-v7 # Capacitor 6 npm i @capgo/capacitor-updater@lts-v6 # Capacitor 5 npm i @capgo/capacitor-updater@lts-v5 ``` Each plugin major version matches the Capacitor major version (v8 → Capacitor 8, v7 → Capacitor 7, v6 → Capacitor 6, v5 → Capacitor 5). Minor versions share the same feature set across all major versions (e.g., 5.34.0, 6.34.0, 7.34.0, and 8.34.0 all include the same features). # CI/CD Integration > Integrating Capgo into your CI/CD pipeline allows you to fully automate the process of building and deploying updates to your app. By leveraging the Capgo CLI and semantic-release, you can ensure consistent, reliable deployments and enable rapid iteration. Integrating Capgo into your CI/CD pipeline allows you to fully automate the process of building and deploying updates to your app. By leveraging the Capgo CLI and semantic-release, you can ensure consistent, reliable deployments and enable rapid iteration. ## Benefits of CI/CD Integration [Section titled “Benefits of CI/CD Integration”](#benefits-of-cicd-integration) * **Automation**: No more manual steps or room for human error. Your entire build, test, and deployment process can be automated from end to end. * **Consistency**: Every deployment follows the same set of steps, ensuring a predictable and repeatable process. This is especially valuable when you have multiple team members contributing code. * **Faster iterations**: With automated deployments, you can ship updates more frequently and with confidence. No more waiting for manual QA or release approvals. ## Capgo CLI [Section titled “Capgo CLI”](#capgo-cli) The Capgo CLI is the key to integrating Capgo into your CI/CD workflow. It provides commands for pushing new bundle versions, managing channels, and more. The most important command for CI/CD integration is `bundle upload`: ```shell npx @capgo/cli@latest bundle upload --channel Production --apikey YOUR_API_KEY ``` If you use encryption you should provide it from one of these ways: **Using a private key file path:** ```shell npx @capgo/cli@latest bundle upload --channel Production --apikey YOUR_API_KEY --key-v2 PRIVATE_KEY_PATH ``` **Using the private key content directly (recommended for CI/CD):** ```shell npx @capgo/cli@latest bundle upload --channel Production --apikey YOUR_API_KEY --key-data-v2 PRIVATE_KEY_CONTENT ``` **Using environment variables (best practice for CI/CD):** ```shell npx @capgo/cli@latest bundle upload --channel Production --apikey YOUR_API_KEY --key-data-v2 "$CAPGO_PRIVATE_KEY" ``` ### Setting up Environment Variables for Encryption [Section titled “Setting up Environment Variables for Encryption”](#setting-up-environment-variables-for-encryption) For CI/CD environments, it’s recommended to store your private key as an environment variable rather than a file. Here’s how to set it up: 1. **Get your private key content:** ```shell cat .capgo_key_v2 | pbcopy ``` This copies the key content to your clipboard. 2. **Add it to your CI/CD environment:** * **GitHub Actions**: Add `CAPGO_PRIVATE_KEY` to your repository secrets * **GitLab CI**: Add it as a masked variable in your project settings * **CircleCI**: Add it as an environment variable in your project settings * **Jenkins**: Add it as a secret text credential 3. **Use it in your pipeline:** ```yaml - run: npx @capgo/cli@latest bundle upload --channel=production --apikey=${{ secrets.CAPGO_API_KEY }} --key-data-v2 "${{ secrets.CAPGO_PRIVATE_KEY }}" ``` **Note**: The `--key-data-v2` flag allows you to pass the private key content directly as a string, making it perfect for environment variables in CI/CD pipelines where you don’t want to create temporary files. This command uploads the current web build to the specified channel. You’ll typically run this as the last step in your CI/CD pipeline, after your web build has completed successfully. ## Setting up Capgo in your CI/CD Pipeline [Section titled “Setting up Capgo in your CI/CD Pipeline”](#setting-up-capgo-in-your-cicd-pipeline) While the exact steps will vary depending on your CI/CD tool of choice, the general process for integrating Capgo looks like this: 1. **Generate an API key**: Log in to the Capgo dashboard and create a new API key. This key will be used to authenticate the CLI in your CI/CD environment. Keep it secret and never commit it to your repository! 2. **Configure the `bundle upload` command**: Add a step to your CI/CD configuration that runs the `bundle upload` command with the appropriate arguments: upload.yml ```yaml - run: npx @capgo/cli@latest bundle upload --channel=production --apikey=${{ secrets.CAPGO_API_KEY }} ``` \n Replace `Production` with the channel you want to deploy to, `${{ secrets.CAPGO_API_KEY }}` with the environment variable holding your API key, and add `--key-data-v2 "${{ secrets.CAPGO_PRIVATE_KEY }}"` if using encryption. 3. **Add the `upload` step after your web build**: Ensure that the `upload` step comes after your web build has completed successfully. This ensures you’re always deploying your latest code.\n Here’s an example configuration for GitHub Actions:\n upload.yml ```yaml name: Deploy to Capgo on: push: branches: [main] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - uses: actions/setup-node@v6 with: node-version: '24' - run: npm ci - run: npm run build - run: npm install -g @capgo/cli - run: npx @capgo/cli@latest bundle upload --channel=production --apikey=${{ secrets.CAPGO_API_KEY }} --key-data-v2 "${{ secrets.CAPGO_PRIVATE_KEY }}" ``` ## Version Management with Semantic-release [Section titled “Version Management with Semantic-release”](#version-management-with-semantic-release) The recommended way to handle versioning with Capgo is to set the version in your `capacitor.config.ts` file by importing it from `package.json`: ```ts import pkg from './package.json' const config: CapacitorConfig = { // ... other config plugins: { CapacitorUpdater: { version: pkg.version, } } } ``` This approach allows you to: 1. Use semantic-release (or any other tool) to update the `package.json` version 2. Build your app with the updated version automatically included 3. Upload the bundle with the correct version Your CI/CD workflow would look like this: ```yaml - run: npm ci - run: npx semantic-release # Updates package.json version - run: npm run build # Builds with new version from capacitor.config - run: npx @capgo/cli@latest bundle upload --channel=production --apikey=${{ secrets.CAPGO_API_KEY }} ``` Here’s a sample `.releaserc` configuration file for semantic-release: ```json { "branches": [ "main", { "name": "beta", "prerelease": true } ], "plugins": [ "@semantic-release/commit-analyzer", "@semantic-release/release-notes-generator", "@semantic-release/changelog", [ "@semantic-release/git", { "assets": ["CHANGELOG.md", "package.json"], "message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}" } ] ] } ``` This configuration does the following: 1. Analyzes commit messages to determine the next version number, following the Conventional Commits spec. 2. Generates release notes based on the commits since the last release. 3. Updates the `CHANGELOG.md` file with the new release notes. 4. Updates the `package.json` version, which will be picked up by your capacitor.config. 5. Commits the updated `CHANGELOG.md`, `package.json`, and any other changed files back to the repository. Make sure to run semantic-release before building your app so that the updated version from `package.json` is included in your build through the capacitor.config. ## Troubleshooting [Section titled “Troubleshooting”](#troubleshooting) If you encounter issues with your Capgo CI/CD integration, here are a few things to check: * **API key**: Ensure your API key is valid and has the necessary permissions. If using an environment variable, double check that it’s set correctly. * **CLI version**: Make sure you’re using the latest version of the Capgo CLI. Older versions may have compatibility issues or lack certain features. * **Build artifacts**: Confirm that your web build is generating the expected output files. The Capgo CLI needs a valid web build to create a bundle. * **Network connectivity**: Check that your CI/CD environment has network access to the Capgo servers. Firewall or proxy issues can sometimes interfere with the `upload` command. If you’re still having trouble, reach out to Capgo support for assistance. They can help troubleshoot any issues with your specific setup. ## Conclusion [Section titled “Conclusion”](#conclusion) Integrating Capgo into your CI/CD pipeline with proper version management can greatly streamline your development workflow. By automating your deployments and versioning through the capacitor.config approach, you can ship updates faster and with more confidence. The recommended approach of setting the version in your `capacitor.config.ts` file and using semantic-release to update `package.json` provides a robust and reliable deployment process that allows you to focus on building great features rather than worrying about manual release steps. For more details on the Capgo CLI commands and options, check out the [CLI reference](/docs/cli/overview). And for a deeper dive into semantic-release configuration, see the [semantic-release docs](https://github.com/semantic-release/semantic-release). Happy deploying! # Deploy a Live Update > Learn how to deploy a live update to your app using Capgo's Live Updates feature, enabling real-time UI and logic updates without app store resubmission. Use Capgo’s Live Updates feature to update the UI and business logic of your app remotely, in real-time. Push JS bundle updates directly to your users without going through the app store to instantly fix bugs and ship new features. This guide assumes you’ve completed the [Capgo Quickstart](/docs/getting-started/quickstart) and have already: 1. Installed the `@capgo/capacitor-updater` SDK in your Capacitor app 2. Configured your app ID and update channel in `capacitor.config.ts` 3. Added in your code the `CapacitorUpdater.notifyAppReady()` method If you haven’t done those steps yet, please go back and complete the quickstart first. [Add an app ](/docs/getting-started/add-an-app/)Add an app to your Capgo account, and install the plugin in your app ## Uploading a Bundle [Section titled “Uploading a Bundle”](#uploading-a-bundle) With the Capgo SDK installed and configured, you’re ready to upload your first live update bundle: 1. Build your web assets: ```shell npm run build ``` 2. Upload the bundle to Capgo: * Console ```shell npx @capgo/cli@latest bundle upload --channel=production ``` * Github Actions .github/workflows/build\_and\_deploy.yml ```yml name: Build source code and send to Capgo concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true on: push: branches: - main jobs: deploy_to_capgo: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v6 - uses: actions/setup-node@v6 with: node-version: '24' - name: Install dependencies run: npm install - name: Build run: npm run build - name: Deploy to Capgo run: npx @capgo/cli@latest bundle upload -a ${{ secrets.CAPGO_TOKEN }} --channel ${{ env.CHANNEL }} env: CAPGO_TOKEN: ${{ secrets.CAPGO_TOKEN }} ``` * Gitlab .gitlab-ci.yml ```yml stages: - build build: stage: build image: node:18 cache: - key: files: - package-lock.json paths: - .node_modules/ script: - npm install - npm run build - npx @capgo/cli@latest bundle upload -a $CAPGO_TOKEN --channel $CAPGO_CHANNEL artifacts: paths: - node_modules/ - dist/ only: - master ``` This will upload a new bundle version to the channel specified in the command. ### Troubleshooting Uploads [Section titled “Troubleshooting Uploads”](#troubleshooting-uploads) If your upload fails, double check: * Your app ID in `capacitor.config.ts` matches your app in the Capgo dashboard * You’re running the upload command from the root of your Capacitor project * Your web assets are built and up to date If you’re still having trouble, go to the [Troubleshooting](/docs/getting-started/troubleshooting/) section. ## Receiving an Update on a Device [Section titled “Receiving an Update on a Device”](#receiving-an-update-on-a-device) Once your bundle is uploaded, you can test the live update on a device: 1. Sync your app to the device: ```shell npx cap sync ios ``` 2. Open another terminal and run the following command to check the update status: ```shell npx @capgo/cli@latest app debug ``` 3. Run your app locally: ```shell npx cap run ios ``` Or open the iOS/Android project in Xcode/Android Studio and do a native run. 4. Keep the app open for about 30 seconds to allow the update to download in the background. 5. The logs will take a few seconds to update and show the update status. 6. Close and reopen the app. You should see your live update applied! Refer back to the [Capgo Quickstart](/docs/getting-started/quickstart#receiving-a-live-update-on-a-device) for more details on testing live updates. ## Next Steps [Section titled “Next Steps”](#next-steps) Congrats on deploying your first live update with Capgo! 🎉 To learn more, review the rest of the [Capgo Live Updates documentation](/docs/live-updates). Some key topics to check out next: * [Targeting Updates with Channels](/docs/live-updates/channels) * [Customizing Update Behavior](/docs/live-updates/update-behavior) * [Live Update Rollbacks](/docs/live-updates/rollbacks) # CLI Onboarding Guide > Complete step-by-step guide to onboard your app with Capgo using the interactive CLI ## Quick Overview [Section titled “Quick Overview”](#quick-overview) The Capgo CLI provides an interactive onboarding that sets up live updates for your Capacitor app. You’ll: 1. ✅ Register your app in Capgo 2. 🔌 Install and configure the updater plugin 3. 🚀 Deploy your first live update 4. 📱 Test the update on your device **Estimated time:** 10-20 minutes (varies based on your internet speed and build time) Tip The onboarding is fully resumable - exit anytime and continue later from where you left off. ## Starting the Onboarding [Section titled “Starting the Onboarding”](#starting-the-onboarding) Run the onboarding command with your API key: ```bash npx @capgo/cli@latest init [APIKEY] ``` You’ll see the welcome message: ```plaintext Capgo onboarding 🛫 ``` ## What Happens During Onboarding [Section titled “What Happens During Onboarding”](#what-happens-during-onboarding) The CLI will guide you through 13 interactive steps: **Setup Phase (Steps 1-6):** * Check your development environment (Xcode/Android Studio) * Add your app to Capgo and create a production channel * Install the `@capgo/capacitor-updater` plugin * Inject the required code into your app * Optionally enable end-to-end encryption * Choose a platform for testing (iOS or Android) **Testing Phase (Steps 7-12):** * Build your app and run it on a device/simulator * Make a visible code change (automatic or manual) * Upload the updated bundle to Capgo * See the live update appear on your device in real-time **Completion (Step 13):** * Your app is ready for live updates! 🎉 ## The 13-Step Onboarding Process [Section titled “The 13-Step Onboarding Process”](#the-13-step-onboarding-process) ### Step 1: Check Prerequisites [Section titled “Step 1: Check Prerequisites”](#step-1-check-prerequisites) The CLI checks your development environment to ensure you have the necessary tools installed. **What’s checked:** * **Xcode** (macOS only) - for iOS development * **Android SDK** - for Android development **Possible outcomes:** ✅ **Both environments found:** ```plaintext ✅ Xcode detected - iOS development ready ✅ Android SDK detected - Android development ready ``` ⚠️ **No environment found:** ```plaintext ⚠️ Xcode not found ⚠️ Android SDK not found ❌ No development environment detected 📱 To develop mobile apps with Capacitor, you need: • For iOS: Xcode (macOS only) - https://developer.apple.com/xcode/ • For Android: Android Studio - https://developer.android.com/studio ``` **Questions you may be asked:** Caution If no development environment is detected, you’ll be asked if you want to continue. It’s recommended to install at least one platform before proceeding. ### Step 2: Add Your App [Section titled “Step 2: Add Your App”](#step-2-add-your-app) The CLI will log you into Capgo and add your app to your account. ```plaintext (spinner) Running: npm @capgo/cli@latest login *** Login Done ✅ ❓ Add {appId} in Capgo? ``` **If your app ID is already taken:** The CLI will suggest alternatives: ```plaintext ❌ App ID "com.example.app" is already taken 💡 Here are some suggestions: 1. com.example.app2 2. com.example.app3 3. com.example.app.new 4. com.example.app.app ❓ What would you like to do? ``` You can choose a suggestion or enter a custom app ID. Note App IDs must follow reverse domain notation (e.g., `com.example.myapp`) ### Step 3: Create Production Channel [Section titled “Step 3: Create Production Channel”](#step-3-create-production-channel) Channels allow you to manage different update streams for your app. ```plaintext ❓ Create default channel production for {appId} in Capgo? ``` Tip **Don’t worry!** This is just for local testing during onboarding. Creating a “production” channel doesn’t mean your updates will go live to customers immediately. You have full control over when updates are deployed. Select **Yes** unless you have specific channel requirements. **If you select Yes:** ```plaintext (spinner) Running: npm @capgo/cli@latest channel add production {appId} --default Channel add Done ✅ (or "Channel already added ✅") ``` A production channel will be created and set as default. This is the recommended option for most users. **If you select No:** ```plaintext If you change your mind, run it for yourself with: "npm @capgo/cli@latest channel add production {appId} --default" ``` You’ll need to create and configure channels manually later. Alternatively, you can: * Set the channel in your `capacitor.config.ts` file * Use the JavaScript `setChannel()` method to dynamically set the channel * Configure channels later from the Capgo web console ### Step 4: Install Updater Plugin [Section titled “Step 4: Install Updater Plugin”](#step-4-install-updater-plugin) The CLI will install the `@capgo/capacitor-updater` plugin compatible with your Capacitor version. ```plaintext ❓ Automatic Install "@capgo/capacitor-updater" dependency in {appId}? ``` **Version compatibility:** * **Capacitor 5**: Installs `@capgo/capacitor-updater` v5 * **Capacitor 6**: Installs `@capgo/capacitor-updater` v6 * **Capacitor 7**: Installs `@capgo/capacitor-updater` v7 * **Capacitor 8+**: Installs latest version Caution Capgo only supports Capacitor v5 and above. If you’re using an older version, you’ll need to upgrade first. **Instant updates option:** After installation, you’ll be asked: ```plaintext ❓ Do you want to set instant updates in {appId}? Read more: https://capgo.app/docs/live-updates/update-behavior/#applying-updates-immediately ``` Tip **What are instant updates?** With instant updates enabled, your app applies updates immediately when backgrounded and reopened. This works seamlessly because Capgo can distribute updates worldwide in under 300ms. Without it (standard mode), updates download in the background and apply on the next app restart. Instant updates are great for faster iteration during development and critical bug fixes in production. **If you select Yes:** * Updates will be configured to apply immediately when the app is backgrounded and reopened * `directUpdate: 'always'` and `autoSplashscreen: true` will be added to your config * Your `capacitor.config.ts` will be updated automatically * **Delta updates** will be automatically enabled - this sends only the files that changed between updates instead of the full bundle, making updates much faster **If you select No:** * Updates will use standard behavior (download in background, apply on next restart) * You can always enable instant updates later by modifying your `capacitor.config.ts` ### Step 5: Add Integration Code [Section titled “Step 5: Add Integration Code”](#step-5-add-integration-code) The CLI will automatically inject the required code into your main application file. ```plaintext ❓ Automatic Add "CapacitorUpdater.notifyAppReady()" code and import in {appId}? ``` **What gets added:** ```typescript import { CapacitorUpdater } from '@capgo/capacitor-updater' CapacitorUpdater.notifyAppReady() ``` **Project type detection:** * **Nuxt.js**: Creates `plugins/capacitorUpdater.client.ts` * **Other frameworks**: Adds to your main entry file Tip **If auto-injection fails**, you can add the code manually to your main application file: **For Nuxt.js:** Create `plugins/capacitorUpdater.client.ts`: ```typescript import { CapacitorUpdater } from '@capgo/capacitor-updater' export default defineNuxtPlugin(() => { CapacitorUpdater.notifyAppReady() }) ``` **For other frameworks:** Add to your main entry file (e.g., `main.ts`, `index.js`, `App.tsx`): ```typescript import { CapacitorUpdater } from '@capgo/capacitor-updater' CapacitorUpdater.notifyAppReady() ``` Place this code after your imports and before your app initialization. For more details, see the [Add an App guide](/docs/getting-started/add-an-app/). ### Step 6: Setup Encryption (Optional) [Section titled “Step 6: Setup Encryption (Optional)”](#step-6-setup-encryption-optional) End-to-end encryption adds an extra security layer for your updates. ```plaintext 🔐 End-to-end encryption ✅ Use this for: Banking, healthcare, or apps with legal encryption requirements ⚠️ Note: Makes debugging harder - skip if you don't need it ❓ Enable end-to-end encryption for {appId} updates? ``` Note Encryption is only available for Capacitor v6 and above. If you enable encryption, the CLI will: 1. Generate encryption keys 2. Offer to sync your Capacitor configuration ### Step 7: Select Platform [Section titled “Step 7: Select Platform”](#step-7-select-platform) Choose which platform to test with during onboarding. ```plaintext 📱 Platform selection for onboarding This is just for testing during onboarding - your app will work on all platforms ❓ Which platform do you want to test with during this onboarding? Options: - iOS - Android ``` Tip This only affects the onboarding process. Your final app will support all platforms. ### Step 8: Build Your Project [Section titled “Step 8: Build Your Project”](#step-8-build-your-project) The CLI will build your app and sync it with Capacitor. ```plaintext ❓ Automatic build {appId} with "npm run build"? ``` **What happens:** 1. Detects your project type 2. Runs your build script 3. Executes `npx cap sync {platform}` **If build script is missing:** You’ll be asked if you want to skip the build or add a build script to your `package.json`. ### Step 9: Run on Device [Section titled “Step 9: Run on Device”](#step-9-run-on-device) Test the initial version of your app on a device or simulator. ```plaintext ❓ Run {appId} on {PLATFORM} device now to test the initial version? ``` If you select **Yes**: ```plaintext (spinner) Running: npx cap run {platform} (device picker appears) App started ✅ 📱 Your app should now be running on your {platform} device with Capgo integrated 🔄 This is your baseline version - we'll create an update next ``` ### Step 10: Make a Test Change [Section titled “Step 10: Make a Test Change”](#step-10-make-a-test-change) Now it’s time to test Capgo’s update system by making a visible change. ```plaintext 🎯 Now let's test Capgo by making a visible change and deploying an update! ❓ How would you like to test the update? Options: - Auto: Let Capgo CLI make a visible change for you - Manual: I'll make changes myself ``` **Auto mode:** The CLI will automatically modify your files to add a visible test banner or change. **Manual mode:** You make your own changes (e.g., change text, colors, or add elements). **Version handling:** ```plaintext ❓ How do you want to handle the version for this update? Options: - Auto: Bump patch version ({currentVersion} → {nextVersion}) - Manual: I'll provide the version number ``` **Build with changes:** ```plaintext ❓ Build {appId} with changes before uploading? ``` Tip If you need to build manually in another terminal, select “No” and build yourself, then continue. ### Step 11: Upload Bundle [Section titled “Step 11: Upload Bundle”](#step-11-upload-bundle) Upload your updated app bundle to Capgo. ```plaintext ❓ Upload the updated {appId} bundle (v{version}) to Capgo? ``` The CLI runs: ```bash npx @capgo/cli@latest bundle upload ``` Tip **Delta updates with Direct Update:** If you enabled instant updates (Direct Update) in Step 4, the CLI will automatically ask if you want to enable delta updates. Delta updates send only the files that changed between versions instead of the entire bundle. Since usually only a few files change between updates, this makes downloads much faster. Select **Yes** for the best experience with instant updates. **Delta updates prompt (if Direct Update is enabled):** ```plaintext 💡 Direct Update (instant updates) is enabled in your config Delta updates send only changed files instead of the full bundle ❓ Enable delta updates for this upload? (Recommended with Direct Update) ``` Caution For monorepos, you may need to provide additional paths to your `package.json` and `node_modules`. **Success:** ```plaintext ✅ Update v{version} uploaded successfully! 🎉 Your updated bundle is now available on Capgo ``` ### Step 12: Test Update on Device [Section titled “Step 12: Test Update on Device”](#step-12-test-update-on-device) Time to see the update in action! ```plaintext 🧪 Time to test the Capgo update system! 📱 Go to your device where the app is running ``` **For instant updates:** ```plaintext 🔄 IMPORTANT: Background your app (swipe up/press home button) and then reopen it ⏱️ The update should be downloaded and applied automatically ``` **For standard updates:** ```plaintext 📱 With standard updates, you will need to: 1. Background the app (swipe up/press home button) to start download 2. Wait a few seconds for download to complete 3. Background and foreground again to see the update ``` **Monitor logs:** ```plaintext ❓ Monitor Capgo logs to verify the update worked? ``` If you select **Yes**, you’ll see live logs from your device showing the update process. ### Step 13: Completion [Section titled “Step 13: Completion”](#step-13-completion) ```plaintext Welcome onboard ✈️! ``` Congratulations! You’ve successfully set up Capgo live updates for your app. ## What You’ve Accomplished [Section titled “What You’ve Accomplished”](#what-youve-accomplished) After completing the onboarding, you have: ✅ App Registered Your app is registered in Capgo with a production channel ✅ Plugin Installed The Capacitor Updater plugin is installed and configured ✅ Code Integrated Integration code is added to your app ✅ Update Tested You’ve successfully deployed and received a live update ## Daily Workflow [Section titled “Daily Workflow”](#daily-workflow) For subsequent updates, use: ```bash npm run build npx @capgo/cli@latest bundle upload --channel=production ``` For more deployment options, see [Deploy a Live Update](/docs/getting-started/deploy/). ## Resuming Onboarding [Section titled “Resuming Onboarding”](#resuming-onboarding) If you exit the onboarding process, you can resume anytime: ```bash npx @capgo/cli@latest init [APIKEY] ``` You’ll see: ```plaintext You have already got to the step {stepNumber}/13 in the previous session ❓ Would you like to continue from where you left off? ``` Tip Progress is saved locally, so you can safely exit and resume the onboarding process. ## Troubleshooting [Section titled “Troubleshooting”](#troubleshooting) ### No Development Environment [Section titled “No Development Environment”](#no-development-environment) **Problem:** Neither Xcode nor Android SDK is detected. **Solution:** * **For iOS**: Install [Xcode](https://developer.apple.com/xcode/) (macOS only) * **For Android**: Install [Android Studio](https://developer.android.com/studio) ### App ID Already Taken [Section titled “App ID Already Taken”](#app-id-already-taken) **Problem:** Your app ID is already registered. **Solution:** Choose one of the suggested alternatives or enter a custom app ID in reverse domain notation. ### Build Script Missing [Section titled “Build Script Missing”](#build-script-missing) **Problem:** No build script found in `package.json`. **Solution:** Add a build script to your `package.json`: ```json { "scripts": { "build": "your-build-command" } } ``` ### Auto-Injection Failed [Section titled “Auto-Injection Failed”](#auto-injection-failed) **Problem:** CLI cannot automatically inject the integration code. **Solution:** Add the code manually to your main file: ```typescript import { CapacitorUpdater } from '@capgo/capacitor-updater' CapacitorUpdater.notifyAppReady() ``` ### Capacitor Version Too Old [Section titled “Capacitor Version Too Old”](#capacitor-version-too-old) **Problem:** Your Capacitor version is below v5. **Solution:** Upgrade Capacitor to v5 or higher: * [Upgrading to Capacitor 5](https://capacitorjs.com/docs/updating/5-0) * [Upgrading to Capacitor 6](https://capacitorjs.com/docs/updating/6-0) * [Upgrading to Capacitor 7](https://capacitorjs.com/docs/updating/7-0) ## Next Steps [Section titled “Next Steps”](#next-steps) Now that you’ve completed onboarding, explore these topics: [ Deploy Updates](/docs/getting-started/deploy/) [Learn how to deploy updates from the Capgo dashboard](/docs/getting-started/deploy/) [ Update Types](/docs/live-updates/update-types/) [Reference of all OTA update types: apply timing, delay conditions, version blocking, and delivery](/docs/live-updates/update-types/) [ CI/CD Integration](/docs/getting-started/cicd-integration/) [Automate your update deployments with CI/CD](/docs/getting-started/cicd-integration/) [ Channels](/docs/live-updates/channels/) [Manage multiple update streams with channels](/docs/live-updates/channels/) [ Encryption](/docs/live-updates/encryption/) [Secure your updates with end-to-end encryption](/docs/live-updates/encryption/) [ Update Behavior](/docs/live-updates/update-behavior/) [Customize when and how updates are applied (direct, delta, etc.)](/docs/live-updates/update-behavior/) ## Getting Help [Section titled “Getting Help”](#getting-help) If you encounter issues during onboarding: * Check the [Troubleshooting Guide](/docs/getting-started/troubleshooting/) * Join the [Discord Community](https://discord.capgo.app) * Review the [FAQ](/docs/faq/) * Contact [Support](/docs/getting-help/) # Overview > Get started with Capgo by learning the key concepts and steps to integrate and deploy live updates to your app. The quickstart tutorial will walk you through the key concepts of Capgo! Concepts that will be explored include: 1. Adding an app to your Capgo account 2. Integrating Capgo with your CI/CD 3. Triggering bundle upload on Capgo by pushing commits 4. Configuring and customizing the Capgo bundle publishing 5. Setting up your app to enable live updates via Capgo 6. Deploying live updates to your app from Capgo Simply follow the guide step-by-step, or navigate directly to the documentation for the component that interests you. [ Start the Tutorial](/docs/getting-started/add-an-app/) [Follow the quickstart tutorial and get up and running with Capgo in no time!](/docs/getting-started/add-an-app/) [ CLI Onboarding Guide](/docs/getting-started/onboarding/) [Complete step-by-step guide for the interactive CLI onboarding process.](/docs/getting-started/onboarding/) [ Ship updates](/docs/getting-started/deploy/) [Ship updates to your app from the Capgo dashboard.](/docs/getting-started/deploy/) [ Automate updates](/docs/getting-started/cicd-integration/) [Integrate Capgo with your CI/CD and trigger bundle uploads on Capgo by pushing commits.](/docs/getting-started/cicd-integration/) [ Trouble Shooting](/docs/getting-started/troubleshooting/) [Common issues and how to solve them.](/docs/getting-started/troubleshooting/) [ Wrap Up](/docs/getting-started/wrapping-up/) [Wrap up the tutorial and get a quick overview of what you’ve learned.](/docs/getting-started/wrapping-up/) Tip The Over-the-Air (OTA) update feature is applicable only for modifications made to HTML, CSS, and JavaScript files. If you make any changes to the native code, such as updates to Capacitor plugins, it is mandatory to resubmit the application to the app store for approval. Bundle Confidentiality Treat every bundle uploaded to Capgo as a public web asset unless you enable Capgo encryption. Private channels control which devices are eligible to receive an update, but they do not make the uploaded bundle confidential. Encryption protects the delivery path and prevents third parties from producing valid encrypted updates, but shipped web assets can still be reverse engineered from the app with enough effort because the public key is distributed in the binary. See [Live Update encryption](/docs/live-updates/encryption/). ## Join Discord Community [Section titled “Join Discord Community”](#join-discord-community) [Join the Capgo Discord Server!](https://discord.capgo.app) ## Maintenance [Section titled “Maintenance”](#maintenance) | Plugin version | Capacitor compatibility | Maintained | | ------------------ | ----------------------- | -------------------------------------------------------- | | v7.\*.\* (≥7.25.0) | v7.\*.\* | ✅ Fully supported | | v6.\*.\* (≥6.25.0) | v6.\*.\* | ✅ Fully supported | | v5.\*.\* (≥5.10.0) | v5.\*.\* | ✅ Fully supported | | v5.\*.\* (<5.10.0) | v5.\*.\* | ⚠️ Deprecated | | v4.\*.\* | v4.\*.\* | ❌ No longer supported | | v3.\*.\* | v3.\*.\* | ❌ No longer supported | | >= 8 | v4.\*.\* | ⚠️ Deprecated due to versioning issues in our CI process | ## Store Guideline Compliance [Section titled “Store Guideline Compliance”](#store-guideline-compliance) Android Google Play and iOS App Store have corresponding guidelines that have rules you should be aware of before integrating the Capacitor-updater solution within your application. ### Google play [Section titled “Google play”](#google-play) Third paragraph of [Device and Network Abuse](https://support.google.com/googleplay/android-developer/answer/9888379/?hl=en) topic describe that updating source code by any method other than Google Play’s update mechanism is restricted. But this restriction does not apply to updating javascript bundles. > This restriction does not apply to code that runs in a virtual machine and has limited access to Android APIs (such as JavaScript in a webview or browser). That fully allows Capacitor-updater as it updates just the JS bundles and won’t update native code. ### App Store [Section titled “App Store”](#app-store) Paragraph **3.3.2**, since back in 2015’s [Apple Developer Program License Agreement](https://developer.apple.com/programs/ios/information/) fully allows performing over-the-air updates of JavaScript and assets - and in its latest version (20170605) [downloadable here](https://developer.apple.com/terms/) this ruling is even broader: > Interpreted code may be downloaded to an Application but only so long as such code: (a) does not change the primary purpose of the Application by providing features or functionality that are inconsistent with the intended and advertised purpose of the Application as submitted to the App Store, (b) does not create a store or storefront for other code or applications, and (c) does not bypass signing, sandbox, or other security features of the OS. Capacitor Updater allows you to follow these rules in full compliance so long as the update you push does not significantly deviate your product from its original App Store approved intent. To further remain in compliance with Apple’s guidelines we suggest that App Store-distributed apps do not enable the `Force update` scenario, since in the [App Store Review Guidelines](https://developer.apple.com/app-store/review/guidelines/) state that: > Apps must not force users to rate the app, review the app, download other apps, or other similar actions in order to access functionality, content, or use of the app. This is not a problem for the default behavior of background update, since it won’t force the user to apply the new version until next time they close the app, but at least you should be aware of that role if you decide to show it. ## Open source [Section titled “Open source”](#open-source) The plugin is under the LGPL-3.0 License and the back-end is AGPL-3.0 License. > 💡 LGPL-3.0 means if someone modifies the code of the plugin, it’s mandatory to publish it, in open-source with the same licensing. If you use the code without modification, that doesn’t concern you. See the issue below for more details check the link 👇 [Licensing? ](https://github.com/Cap-go/capacitor-updater/issues/7) [Try GPTS Capgo to Get help instead of reading the docs ](https://chat.openai.com/g/g-3dMwHbF2w-capgo-doc-gpt) > You can include it in your app without worrying ## Final Notes [Section titled “Final Notes”](#final-notes) If you self-host and find this tool useful, please consider supporting my work by becoming a [GitHub sponsor](https://github.com/sponsors/riderx/). I made a bet to open-source all the code I built here instead of paywalling it. By opening it up instead of fighting and hiding, I believe we can make the world a better place. To make this possible, it’s necessary for all of us to do our part, including you 🥹. If Capgo cloud doesn’t meet your needs, you can back a bootstrapped Maker [here](https://github.com/sponsors/riderx/) on your own terms. ## Simple Maths [Section titled “Simple Maths”](#simple-maths) The price of the basic plan: $14\*12 = $168 a year. While average dev/hour = $60. That means that 3 hours wasted of dev time on self-host allows you to pay for a whole year, if you spent more than 3 hours you’re losing money ^^ # Troubleshooting > Resolve common issues encountered while using Capgo with detailed troubleshooting steps and advanced options for upload and debugging. Here are some common issues you might encounter while using Capgo and how to resolve them. 🚀 Need Expert Help? Stuck with a complex issue? Our expert team is here to help! Get personalized support, code reviews, and custom solutions tailored to your specific needs. [Get Professional Support](/consulting/) ### Upload failures [Section titled “Upload failures”](#upload-failures) If your bundle upload fails, double check: * Your app ID in `capacitor.config.ts` matches your app in the Capgo dashboard * You’re running the upload command from the root of your Capacitor project * Your web assets are built and up to date #### Advanced upload options [Section titled “Advanced upload options”](#advanced-upload-options) The Capgo CLI provides some additional flags to help with common upload issues: * `--tus`: Uses the [tus resumable upload protocol](https://tus.io/) for more reliable uploads of large bundles or on poor network connections. If your bundle is over 10MB or you’re on a spotty connection, consider using `--tus`: ```shell npx @capgo/cli@latest bundle upload --tus ``` * `--package-json` and `--node-modules`: Tells Capgo where to find your root `package.json` and `node_modules` if your app uses a non-standard structure like a monorepo or npm workspace. Pass the path to the root `package.json` and the `--node_modules` path: ```shell npx @capgo/cli@latest bundle upload --package-json=path/to/package.json --node_modules=path/to/node_modules ``` Capgo needs this information to correctly bundle your app’s dependencies. You can combine these flags with other options like `--channel` as needed. See the [Capgo CLI docs](/docs/cli/overview/) for full details on the available upload options. If you’re still having trouble with uploads, reach out to [Capgo support](https://support.capgo.app) for further assistance. ### Debugging Updates [Section titled “Debugging Updates”](#debugging-updates) If you’re encountering issues with live updates, the Capgo debug command is a helpful tool for troubleshooting. To use it: 1. Run the following command in your project directory: ```shell npx @capgo/cli@latest app debug ``` 2. Launch your app on a device or emulator and perform the action that should trigger an update (e.g. reopening the app after uploading a new bundle). 3. Watch the output of the debug command. It will log information about the update process, including: * When the app checks for an update * If an update is found and what version it is * Download and installation progress for the update * Any errors that occur during the update process 4. Use the debug logs to identify where the issue is occurring. For example: * If no update is found, double check that your bundle was uploaded successfully and the app is configured to use the correct channel. * If the update downloads but doesn’t install, make sure you’ve called `CapacitorUpdater.notifyAppReady()` and that the app was fully closed and reopened. * If you see an error message, look up that specific error in the Capgo docs or reach out to support for help. The debug command is especially useful for identifying issues with the update download and installation process. If the logs show the expected update version was found but not ultimately applied, focus your troubleshooting on the steps after the download. ### Debugging with Native Logs [Section titled “Debugging with Native Logs”](#debugging-with-native-logs) In addition to the Capgo debug command, the native logs on Android, iOS, and Electron can provide valuable troubleshooting information, especially for issues on the native side of the update process. #### Android Logs [Section titled “Android Logs”](#android-logs) To access the Android logs: 1. Connect your device or start your emulator 2. Open Android Studio and select “View > Tool Windows > Logcat” 3. In the Logcat window, filter the logs to just your app’s process by selecting it from the dropdown at the top 4. Look for any lines that include `Capgo` to find the SDK logs Alternatively, you can use the `adb logcat` command and grep for `Capgo` to filter the logs. The Capgo SDK will log key events during the update process, such as: * When an update check is initiated * If an update is found and what version it is * When the update download starts and completes * When the update installation is triggered * Any errors that occur during the native update steps Common Android-specific issues you might see in the logs include: * Network connectivity problems preventing the update download * File permissions errors when saving or reading the update bundle * Out of storage space for the update bundle * Failure to restart the app after the update is installed #### iOS Logs [Section titled “iOS Logs”](#ios-logs) To access the iOS logs: 1. Connect your device or start your simulator 2. Open Xcode and go to “Window > Devices and Simulators” 3. Select your device and click on “Open Console” 4. In the console output, look for any lines that include `Capgo` to find the SDK logs You can also use the `log stream` command in the terminal and grep for `Capgo` to filter the logs. Similar to Android, the Capgo SDK will log key iOS-side events: * Update check initiation and result * Download start, progress, and completion * Installation trigger and result * Any errors during the native update process iOS-specific issues you might identify in the logs include: * SSL certificate problems when downloading the update * App transport security blocking the update download * Insufficient storage space for the update bundle * Failure to properly extract or apply the update bundle #### Electron Logs [Section titled “Electron Logs”](#electron-logs) For Electron apps, check both the main process and renderer process output: 1. Run the Electron app from your terminal using your normal launch command (for example `bun run electron:dev` or `bun run electron:serve`) and watch the terminal output for startup, update checks, and network errors. 2. Open DevTools in the renderer window (View → Toggle Developer Tools) and inspect console logs and failed network requests while reproducing the update flow. 3. For packaged apps, check OS log tools for crashes or startup failures: * **macOS**: open `Console.app` and filter on your app name * **Windows**: open **Event Viewer** → **Windows Logs** → **Application** * **Linux**: use your desktop log viewer or `journalctl` for your app process When debugging updates, compare messages from both main-process and renderer-process logs to separate Electron bootstrap issues from Capgo update lifecycle issues. Across platforms, the native logs provide a lower-level view into the update process, with more details on the native implementation. They are especially useful for identifying issues that occur outside of the Capgo JavaScript layer. When troubleshooting a tricky live update problem, it’s a good idea to capture both the Capgo debug logs and the native logs for a comprehensive picture of what’s happening. The two logs together will give you the best chance of identifying and resolving the issue. ### Updates not applying [Section titled “Updates not applying”](#updates-not-applying) If you’ve uploaded a bundle but aren’t seeing the changes on your device: * Make sure you’ve called `CapacitorUpdater.notifyAppReady()` in your app code as shown in the [quickstart](/docs/getting-started/quickstart) * Check that your device is connected to the internet and the Capgo debug logs show the update was downloaded * Try fully closing and reopening the app, as updates are only applied on a fresh launch * Look for any errors in the native logs that might indicate a problem applying the update Refer to the [deploying live updates](/docs/getting-started/deploy) guide for more details on the update process. If you’re still stuck, use the `npx @capgo/cli@latest app debug` command and native logs to get more visibility into what’s happening. ### Common update failure codes [Section titled “Common update failure codes”](#common-update-failure-codes) If your logs show backend errors such as `disable_auto_update_to_major`, `semver_error`, or `cannot_update_via_private_channel`, use the dedicated guide: * [Common Update Problems](/docs/plugins/updater/commonproblems/) It explains what each common code means, why it happens, and how to fix it. ## SDK Installation [Section titled “SDK Installation”](#sdk-installation) If you’re having trouble installing the Capgo SDK, make sure: * Your app is using a supported version of Capacitor (4.0 or newer) * You’ve followed the [quickstart](/docs/getting-started/quickstart) steps in order, including syncing your app after installing the SDK ## CI/CD Integration [Section titled “CI/CD Integration”](#cicd-integration) For issues with triggering Capgo uploads from your CI/CD pipeline: * Double check your Capgo authentication token is set up correctly * Make sure you’re running the upload command after your web assets are built * Check that the upload command is using the correct channel name for your target environment See the [CI/CD integration](/docs/getting-started/cicd-integration/) docs for more troubleshooting tips. You can also use the `npx @capgo/cli@latest app debug` command to confirm if your CI/CD-triggered updates are being received by the app. # Wrapping up > Wrap up your Capgo journey with a concise overview of key concepts and next steps, ensuring a solid foundation for future exploration and mastery. Now that you have completed the quickstart guide, you should have a basic understanding of the key concepts of Capgo! The key concepts you have learned in this guide are: 1. Adding an app to your Capgo account 2. Integrating Capgo with your CI/CD pipeline 3. Triggering bundle uploads to Capgo on new commits 4. Configuring your app to enable live updates with the Capgo SDK 5. Deploying live updates to your app from the Capgo dashboard But there’s still more to learn about Capgo! Continue exploring the docs or check out some of these key topics: [ CI/CD Integration](/docs/getting-started/cicd-integration/) [Already have a CI/CD pipeline? Learn how to incorporate Capgo into your existing workflow.](/docs/getting-started/cicd-integration/) [ Live Updates](/docs/live-updates/) [Dive deeper into Capgo’s live update features and best practices.](/docs/live-updates/) [ FAQ](/docs/faq/) [Find answers to common questions about Capgo.](/docs/faq/) [ Troubleshooting](/docs/getting-started/troubleshooting/) [Get help with common issues that can come up while using Capgo.](/docs/getting-started/troubleshooting/) # How to > A comprehensive guide to Capgo, offering detailed tutorials, insightful tips, and advanced techniques to enhance your effective usage of the platform [How version works in Capgo ](https://capgo.app/blog/how-version-work-in-capgo/)capgo.app [How to release major version in Capgo ](https://capgo.app/blog/how-to-release-major-version-in-capgo/)capgo.app [How to send specific update to one user or a group ](https://capgo.app/blog/how-to-send-specific-version-to-users/)capgo.app ## CI / CD [Section titled “CI / CD”](#ci--cd) [Automatic build and release with GitHub Actions ](https://capgo.app/blog/automatic-build-and-release-with-github-actions/)capgo.app [Manage development and production build with GitHub Actions ](https://capgo.app/blog/automatic-build-and-release-with-github-actions/)capgo.app ## Contributing [Section titled “Contributing”](#contributing) [Contributing to Capgo open source ](https://github.com/Cap-go/capgo/blob/main/CONTRIBUTING.md)github.com # Overview > Discover how Capgo's Live Updates enable seamless JavaScript bundle updates, allowing you to push changes directly to users without app store delays. Use Capgo’s Live Updates feature to update the JavaScript bundles of your app remotely, in real-time. Push JS updates directly to your users on iOS, Android, and Electron without going through store-level review cycles to fix bugs and ship new features faster. Note Live Updates are limited to JavaScript bundle changes. If you need to update native code, such as adding or removing a plugin or changing native project configuration, you’ll need to submit a new binary build through the usual platform distribution process. Public Asset Model Unencrypted bundles uploaded to Capgo should be treated as public delivery assets. Channels determine which devices are offered an update, but channel privacy does not make the underlying bundle confidential. Encryption adds protection in storage and transit and stops third parties from producing valid encrypted updates, but it does not make shipped web assets impossible to inspect because the app contains the public key needed for decryption. See [end-to-end encryption](/docs/live-updates/encryption/) for the exact threat model. ## How Live Updates Work [Section titled “How Live Updates Work”](#how-live-updates-work) Capgo’s Live Update system has two key components: 1. The Capgo SDK, which you install in your app. The SDK checks for available updates and downloads them in the background. 2. Channels, which let you target updates to specific groups of users. You can use channels to manage different release tracks, such as `Production`, `Staging`, and `Dev`. When you upload a new JS bundle to Capgo and assign it to a channel, the Capgo SDK in apps configured for that channel will detect the update and download it. The next time the app restarts, the new bundle will be loaded. ## Why Capgo Logs Matter (marketing view) [Section titled “Why Capgo Logs Matter (marketing view)”](#why-capgo-logs-matter-marketing-view) * **Instant x-ray of every rollout**: Per-device timelines show checks, downloads, installs, policy blocks, and rollbacks, so you know exactly what happened—no guesswork or “it works on my phone” debates. * **Faster incident response**: Alert-like codes (e.g., rate limits, checksum fails, notifyAppReady misses) surface before users start flooding support, letting you ship a fix or rollback in minutes. * **Channel policy proof**: Logs verify that guardrails (block majors, disable emulators/dev builds, platform limits) are actively protecting production. * **Revenue & reputation protection**: See when updates stall on poor networks or hit plan limits, so you can intervene before conversions, sessions, or reviews drop. * **Single source of truth**: Product, QA, and Support share the same cloud log stream—no digging through Xcode/Android Studio or DM’ing engineers for native logs. ## Getting Started [Section titled “Getting Started”](#getting-started) To start using Live Updates, follow these steps: 1. Complete the [Capgo Quickstart](/docs/getting-started/quickstart) to set up your app in Capgo and install the Capgo SDK. 2. In your app code, call `CapacitorUpdater.notifyAppReady()` after your app has finished initializing. This tells the Capgo SDK that your app is ready to receive updates. 3. Build your JS bundle and upload it to Capgo: ```shell npm run build npx @capgo/cli@latest bundle upload --channel=production ``` 4. Open your app and wait for the update to download. You can check the status with: ```shell npx @capgo/cli@latest app debug ``` 5. Once the update is downloaded, close and reopen your app to load the new bundle. See the [Deploying Live Updates](/docs/getting-started/deploy) guide for more details. ## Next Steps [Section titled “Next Steps”](#next-steps) [ Update Types](/docs/live-updates/update-types/) [Reference of all OTA update types: apply timing, delay conditions, version blocking, and delivery.](/docs/live-updates/update-types/) [ Channels](/docs/live-updates/channels/) [Learn how to use channels to manage different release tracks and target updates to specific users.](/docs/live-updates/channels/) [ Rollbacks](/docs/live-updates/rollbacks/) [Discover how to roll back to a previous JS bundle version if an update causes issues.](/docs/live-updates/rollbacks/) [ Update Behavior](/docs/live-updates/update-behavior/) [Customize how and when updates are downloaded and applied in your app.](/docs/live-updates/update-behavior/) [ Fast Updates](/docs/live-updates/differentials/) [Learn how to use fast updates to speed up the update process.](/docs/live-updates/differentials/) # Breaking Changes > How to handle breaking changes with versioned channels This documentation explains how to handle breaking changes in your app using versioned channels. This approach allows you to maintain different versions of your app while ensuring users receive compatible updates. ## Example Scenario [Section titled “Example Scenario”](#example-scenario) Let’s say you have: * App version 1.2.3 (old version) - uses production channel * App version 2.0.0 (new version with breaking changes) - uses v2 channel * Live update 1.2.4 (compatible with 1.2.3) * Live update 2.0.1 (compatible with 2.0.0) ## Strategy: Always Use defaultChannel for Major Versions [Section titled “Strategy: Always Use defaultChannel for Major Versions”](#strategy-always-use-defaultchannel-for-major-versions) **Recommended approach:** Set a `defaultChannel` for every major version. This ensures you can always push updates to specific user groups without relying on dynamic channel assignment. ```ts // Version 1.x releases defaultChannel: 'v1' // Version 2.x releases defaultChannel: 'v2' // Version 3.x releases (future) defaultChannel: 'v3' ``` Tip **Benefits of this approach:** * **Always have control** over which users receive updates * **No dynamic channel switching** needed in your app code * **Clear separation** between different app versions * **Flexibility** to push updates to any specific version group ## 1. Create Channel for New Version [Section titled “1. Create Channel for New Version”](#1-create-channel-for-new-version) ```bash # Create channel for version 2.x npx @capgo/cli channel create v2 ``` ## 2. Update Capacitor Config for Version 2.0.0 [Section titled “2. Update Capacitor Config for Version 2.0.0”](#2-update-capacitor-config-for-version-200) Update your Capacitor config before building version 2.0.0 for the app store: capacitor.config.ts ```ts import { CapacitorConfig } from '@capacitor/cli'; const config: CapacitorConfig = { appId: 'com.example.app', appName: 'Example App', plugins: { CapacitorUpdater: { // ... other options defaultChannel: 'v2' // All 2.0.0 users will use v2 channel } } }; export default config; ``` Note **For version 1.x:** If you didn’t set a `defaultChannel` initially, version 1.x users are on the `production` channel. For future major versions, always set a specific channel like `v3`, `v4`, etc. ## 3. Manage Separate Code Branches [Section titled “3. Manage Separate Code Branches”](#3-manage-separate-code-branches) Create separate git branches to maintain compatibility between app versions: ```bash # Create and maintain a branch for version 1.x updates git checkout -b v1-maintenance git push origin v1-maintenance # Your main branch continues with version 2.x development git checkout main ``` **Critical:** Never push JavaScript bundles to older apps that expect native code/APIs they don’t have. Always build updates from the appropriate branch: * **v1-maintenance branch**: For updates to 1.x apps (production channel) * **main branch**: For updates to 2.x apps (v2 channel) ## 4. Upload Bundles to Respective Channels [Section titled “4. Upload Bundles to Respective Channels”](#4-upload-bundles-to-respective-channels) ```bash # For 1.x updates: Build from v1-maintenance branch git checkout v1-maintenance # Make your 1.x compatible changes here npx @capgo/cli bundle upload --channel production # For 2.x updates: Build from main branch git checkout main # Make your 2.x changes here npx @capgo/cli bundle upload --channel v2 ``` ## 5. Enable Self-Assignment [Section titled “5. Enable Self-Assignment”](#5-enable-self-assignment) ```bash # Allow apps to self-assign to v2 channel npx @capgo/cli channel set v2 --self-assign ``` ## 6. Deploy to App Store [Section titled “6. Deploy to App Store”](#6-deploy-to-app-store) Build and deploy version 2.0.0 to the app store. All users who download this version (whether new users or existing users upgrading) will automatically use the v2 channel because it’s configured in the app bundle. Note **No code changes needed!** Since `defaultChannel: 'v2'` is bundled with the app store version, all users downloading version 2.0.0 will automatically use the correct channel. ## Scaling to Future Versions [Section titled “Scaling to Future Versions”](#scaling-to-future-versions) When you release version 3.0.0 with more breaking changes: ```bash # Create channel for version 3.x npx @capgo/cli channel create v3 ``` ```ts // capacitor.config.ts for version 3.0.0 const config: CapacitorConfig = { // ... plugins: { CapacitorUpdater: { defaultChannel: 'v3' // Version 3.x users } } }; ``` Now you can push updates to any version: * `production` channel → Version 1.x users * `v2` channel → Version 2.x users * `v3` channel → Version 3.x users ## 7. Cleanup (After Migration) [Section titled “7. Cleanup (After Migration)”](#7-cleanup-after-migration) Once all users have migrated to version 2.x (count 3-4 months): 1. Remove `defaultChannel` from your Capacitor config 2. Delete the v2 channel: ```bash npx @capgo/cli channel delete v2 ``` 3. Delete the v1-maintenance branch: ```bash git branch -d v1-maintenance git push origin --delete v1-maintenance ``` Tip This approach ensures users only receive updates compatible with their app version Always test updates thoroughly in each channel before deployment Note You can safely delete the v2 channel in Capgo even if some users still have the channel override. They will automatically receive updates from the production channel instead. ## Maintaining Version 1.x Updates [Section titled “Maintaining Version 1.x Updates”](#maintaining-version-1x-updates) To send updates compatible with version 1.x: 1. Switch to the v1-maintenance branch: ```bash git checkout v1-maintenance ``` 2. Make your changes and commit: ```bash # Make 1.x compatible changes git add . git commit -m "Fix for v1.x" git push origin v1-maintenance ``` 3. Build and upload to production channel: ```bash npx @capgo/cli bundle upload --channel production ``` Tip Keep your v1-maintenance branch up to date with bug fixes that are compatible with version 1.x, but never merge breaking changes from main # Channels > Learn how to manage and configure Live Update channels in Capgo, enabling seamless app updates by directing specific JS bundle builds to devices configured for those channels. A Live Update channel points to a specific JS bundle build of your app that will be shared with any devices configured to listen to that channel for updates. When you [install the Capgo Live Updates SDK](/docs/getting-started/quickstart/) in your app, any native binary configured to that channel will check for available updates whenever the app is launched. You can change the build a channel points to at any time and can also roll back to previous builds if needed. Channels Do Not Provide Confidentiality Channels control update eligibility, not bundle secrecy. Even if a channel is private or self-assignment is disabled, any unencrypted bundle uploaded to Capgo should still be treated as a public asset delivered to clients. Encryption protects the delivery path and authenticity of updates, but shipped bundles can still be reverse engineered from the distributed app with enough effort because the public key is part of the client. See [Live Update encryption](/docs/live-updates/encryption/) for details. ## How a device picks a channel (precedence) [Section titled “How a device picks a channel (precedence)”](#how-a-device-picks-a-channel-precedence) When a device checks for an update, Capgo decides which channel to use in this strict order (highest priority first): 1. **Forced device mapping (Dashboard)** – Manually pin a specific device ID to a channel. Use for urgent debugging or controlled testing with a single real user. This always wins. 2. **Cloud override (per‑device) via Dashboard or API** – Created when you change the device’s channel in the dashboard or via API. Use for QA users switching between feature / PR channels or to reproduce a user issue. Reinstalling the binary does not clear it; deleting the device entry does. Instant Channel Switching with setChannel() **Starting from plugin version 5.34.0, 6.34.0, 7.34.0, or 8.0.0** (depending on your major version), `setChannel()` works differently: it contacts the backend to **validate** that the channel is allowed (checking if self-assignment is enabled for that channel), then stores the channel **locally on the device** as `defaultChannel`. This means the new channel takes effect **instantly** for the next update check—no waiting for replication. Previously, `setChannel()` saved the channel override to the backend database (like Dashboard or API changes), and devices had to wait for data replication (up to 2 minutes) before the new channel was recognized. The new behavior only reads from the backend (for validation) and stores locally, making channel switches instant. **Note:** Even if a channel becomes disallowed after being set locally, the backend will still validate the channel during update checks, so security is maintained. **Important:** When channel changes are made via the Dashboard or API, there is still a replication lag of up to 2 minutes before all edge servers reflect the change. For instant channel switching, use `setChannel()` from your app code—it validates with the backend, then sets the channel locally for immediate effect. 3. **Capacitor config `defaultChannel` (test build default)** – If present in `capacitor.config.*` and no force/override exists, the app starts on this channel (e.g. `beta`, `qa`, `pr-123`). Intended for TestFlight / internal builds so testers land on a pre‑release channel automatically. Production builds typically leave this unset. 4. **Cloud Default Channel (primary path \~99% of users)** – If you mark a default channel in the dashboard, all normal end‑users (no force, no override, no config defaultChannel) attach here. Change it to roll out or roll back instantly—no new binary. If you have platform-specific defaults (for example, one iOS-only, one Android-only, one Electron-only), each device lands on the default matching its platform. Leaving the cloud default unset is allowed; in that case the device must match on steps 1–3 to receive updates. Best practice: * Treat 1–3 as exception / testing layers; when you set a cloud default, real users should flow into it. If you choose not to set one, be deliberate about how users attach (typically via `defaultChannel` in config or per-device overrides). * Only configure `defaultChannel` in binaries you explicitly ship to testers. Leaving it unset keeps production logic centralized in the dashboard. * Use `setChannel()` sparingly in production—mainly for QA or targeted diagnostics. If a channel is disabled for the platform (iOS/Android/Electron toggles) when it would otherwise be chosen, the selection process skips it and continues down the list. > Summary: Force > Override > Config `defaultChannel` > Cloud Default. ## Default Channel Behavior [Section titled “Default Channel Behavior”](#default-channel-behavior) Setting a cloud default is optional, but it usually serves as the catch-all path for new devices. Without one, only devices that match on forced mappings, overrides, or a `defaultChannel` in the Capacitor config will receive updates. When you do choose to mark defaults, keep these patterns in mind: * **Single default (most common)** – If a channel has iOS, Android, and Electron enabled, it becomes the lone default; any device without overrides will attach here. * **Platform-specific defaults** – If you split channels by platform (for example, `ios-production` with only iOS enabled, `android-production` with only Android enabled, and `electron-production` with only Electron enabled), mark each one as the default for its platform. iOS devices go to the iOS default, Android devices go to the Android default, and Electron apps go to the Electron default. Remember that the cloud default and `defaultChannel` in `capacitor.config.*` both occupy the same decision layer. If you set a cloud default, you don’t need to duplicate the value in your Capacitor config—leave `defaultChannel` empty for production builds. Reserve `defaultChannel` for binaries you intentionally ship to testers or QA when you want them to start on a non-production channel even if the cloud default is different. You can change defaults at any time in the dashboard. When you swap a default, new devices obey the new routing immediately and existing devices follow the normal precedence rules the next time they check in. ## Setting up a Channel [Section titled “Setting up a Channel”](#setting-up-a-channel) During onboarding you create the first channel (most teams name it “Production”), but nothing is locked—you can rename or delete any channel at any time. To add additional channels later: 1. Go to the “Channels” section of the Capgo dashboard 2. Click the “New Channel” button 3. Enter a name for the channel and click “Create” Channel names can be anything you’d like. A common strategy is to match channels to your development stages, such as: * `Development` - for testing live updates on local devices or emulators * `QA` - for your QA team to verify updates before wider release * `Staging` - for final testing in a production-like environment * `Production` - for the version of your app that end users receive from the app stores ## Configuring the Channel in Your App [Section titled “Configuring the Channel in Your App”](#configuring-the-channel-in-your-app) With your channels created, you need to configure your app to listen to the appropriate channel. In this example, we’ll use the `Development` channel. Open your `capacitor.config.ts` (or `capacitor.config.json`) file. Under the `plugins` section, optionally set `defaultChannel` for **test builds** (internal / QA). For production builds, prefer omitting it so devices use the Cloud Default unless explicitly overridden. ```ts import { CapacitorConfig } from '@capacitor/cli'; const config: CapacitorConfig = { plugins: { CapacitorUpdater: { // For a QA/TestFlight build – testers start on the Development channel automatically. defaultChannel: 'Development', // Production builds usually omit this so users attach to the Cloud Default channel. }, }, }; ``` Next, build your web app and run `npx cap sync` to copy the updated config file to your iOS, Android, and Electron projects. If you skip this sync step, your native projects will continue to use whichever channel they were previously configured for. Caution Channel selection order: Force > Override (`setChannel` / dashboard) > Config `defaultChannel` > Cloud Default. Use `defaultChannel` only in test/internal builds; leave it out for production so users follow the Cloud Default (when set) instead of duplicating the routing in native config. You can still force (pin) a device or apply an override later—those immediately supersede the config value. > Channel names are case sensitive. ## Channel Options and Strategies [Section titled “Channel Options and Strategies”](#channel-options-and-strategies) Channels have several options that control who can receive updates and how updates are delivered. The most important ones are below. You can configure these from the web app, the CLI, or the Public API. * Default channel: Optionally mark the channel or platform-specific channels that new devices attach to. See “Default Channel Behavior” for routing scenarios. * Platform filters: Enable or disable delivery to `iOS`, `Android`, or `Electron` devices per channel. * Disable auto downgrade under native: Prevents sending an update when the device’s native app version is newer than the channel’s bundle (for example, device on 1.2.3 while channel has 1.2.2). * Allow development builds: Permit updates to development builds (useful for testing). * Allow emulator devices: Permit updates to emulators/simulators (useful for testing). * Allow device self‑assignment: Lets the app switch to this channel at runtime using `setChannel`. If disabled, `setChannel` will fail for this channel. ### Disable Auto Update strategies [Section titled “Disable Auto Update strategies”](#disable-auto-update-strategies) Use this to restrict which kinds of updates the channel will automatically deliver. Options: * major: Block cross‑major updates (0.0.0 → 1.0.0). Minor and patch updates still allowed. * minor: Block cross‑minor updates (e.g., 1.1.0 → 1.2.0) and majors. Patch updates still allowed. Note: does not block 0.1.0 → 1.1.0. * patch: Very strict. Allows only increasing patch versions within the same major and minor. Examples: 0.0.311 → 0.0.314 ✅, 0.1.312 → 0.0.314 ❌, 1.0.312 → 0.0.314 ❌. * metadata: Require a minimum update version metadata on each bundle. Configure via CLI using `--min-update-version` or `--auto-min-update-version`. If missing, the channel is marked misconfigured and updates will be rejected until set. * none: Allow all updates according to semver compatibility. Learn more details and examples in Disable updates strategy at /docs/cli/commands/#disable-updates-strategy. Example (CLI): ```bash # Block major updates on the Production channel npx @capgo/cli@latest channel set production com.example.app \ --disable-auto-update major # Allow devices to self-assign to the Beta channel npx @capgo/cli@latest channel set beta com.example.app --self-assign ``` ### Using setChannel() from Your App [Section titled “Using setChannel() from Your App”](#using-setchannel-from-your-app) The `setChannel()` method allows your app to programmatically switch channels at runtime. This is particularly useful for: * QA/debug menus where testers can switch between channels * Beta program opt-in flows * Feature flag implementations * A/B testing scenarios ```typescript import { CapacitorUpdater } from '@capgo/capacitor-updater'; // Switch to the beta channel await CapacitorUpdater.setChannel({ channel: 'beta' }); // Optionally trigger an immediate update check after switching await CapacitorUpdater.setChannel({ channel: 'beta', triggerAutoUpdate: true }); ``` How setChannel() Works (v5.34.0+ / v6.34.0+ / v7.34.0+ / v8.0.0+) When `setChannel()` is called: 1. **Backend validation (read-only)**: A request is sent to the Capgo backend to validate the channel is allowed (checking self-assignment permissions) 2. **Local storage update**: If validation passes, the channel is saved to the device’s local storage as `defaultChannel` 3. **Instant effect**: The next update check uses the new channel immediately (no waiting for replication) **Why this matters:** In older versions, `setChannel()` saved the channel override to the backend database (same as Dashboard or API changes). Devices had to wait for backend replication (up to 2 minutes) before the channel change took effect. Now, `setChannel()` only reads from the backend (for validation) and stores locally, making channel switches instant. **Security note:** Even if a channel’s permissions change after being set locally (e.g., self-assignment is disabled), the backend will still validate the channel during update checks, ensuring security is maintained. **Comparison of channel change methods:** | Method | Effect Time | Persisted Where | Use Case | | -------------------------- | ----------- | ------------------- | -------------------------------------------- | | `setChannel()` from plugin | **Instant** | Device only (local) | User-initiated channel switching in-app | | Dashboard device override | Up to 2 min | Backend database | Admin-initiated changes for specific devices | | API channel assignment | Up to 2 min | Backend database | Automated backend integrations | For the best user experience when building channel-switching UIs, always use the plugin’s `setChannel()` method. Minimum versions for local-only channel switching: **5.34.0**, **6.34.0**, **7.34.0**, or **8.0.0** (depending on your major version). Each minor version number corresponds to the same feature set across all major versions (e.g., X.34.0 includes the same features whether X is 5, 6, 7, or 8). See [plugin installation](/docs/getting-started/add-an-app/) for version tags. ## Assigning a Bundle to a Channel [Section titled “Assigning a Bundle to a Channel”](#assigning-a-bundle-to-a-channel) To deploy a live update, you need to upload a new JS bundle build and assign it to a channel. You can do this in one step with the Capgo CLI: ```shell npx @capgo/cli@latest bundle upload --channel=Development ``` This will upload your built web assets and set the new bundle as the active build for the `Development` channel. Any apps configured to listen to that channel will receive the update the next time they check for one. You can also assign builds to channels from the “Bundles” section of the Capgo dashboard. Click the menu icon next to a build and select “Assign to Channel” to choose the channel for that build. ## Bundle Versioning and Channels [Section titled “Bundle Versioning and Channels”](#bundle-versioning-and-channels) It’s important to note that bundles in Capgo are global to your app, not specific to individual channels. The same bundle can be assigned to multiple channels. When versioning your bundles, we recommend using semantic versioning [semver](https://semver.org/) with pre-release identifiers for channel-specific builds. For example, a beta release might be versioned as `1.2.3-beta.1`. This approach has several benefits: * It clearly communicates the relationship between builds. `1.2.3-beta.1` is obviously a pre-release of `1.2.3`. * It allows for reusing version numbers across channels, reducing confusion. * It enables clear rollback paths. If you need to roll back from `1.2.3`, you know `1.2.2` is the previous stable release. Here’s an example of how you might align your bundle versions with a typical channel setup: * `Development` channel: `1.2.3-dev.1`, `1.2.3-dev.2`, etc. * `QA` channel: `1.2.3-qa.1`, `1.2.3-qa.2`, etc. * `Staging` channel: `1.2.3-rc.1`, `1.2.3-rc.2`, etc. * `Production` channel: `1.2.3`, `1.2.4`, etc. Using semver with pre-release identifiers is a recommended approach, but not strictly required. The key is to find a versioning scheme that clearly communicates the relationships between your builds and aligns with your team’s development process. ## Rolling Back a Live Update [Section titled “Rolling Back a Live Update”](#rolling-back-a-live-update) If you deploy a live update that introduces a bug or otherwise needs to be reverted, you can easily roll back to a previous build. From the “Channels” section of the dashboard: 1. Click the name of the channel you want to roll back 2. Find the build you want to revert to and click the crown icon ![Rollback build](/select_bundle.webp) 3. Confirm the action The selected build will immediately become the active build for that channel again. Apps will receive the rolled back version the next time they check for an update. ## Automating Deployments [Section titled “Automating Deployments”](#automating-deployments) For more advanced workflows, you can automate your live update deployments as part of your CI/CD pipeline. By integrating Capgo into your build process, you can automatically upload new bundles and assign them to channels whenever you push to certain branches or create new releases. Check out the [CI/CD Integration](/docs/getting-started/cicd-integration/) docs to learn more about automating Capgo live updates. ## Deploying to a Device [Section titled “Deploying to a Device”](#deploying-to-a-device) Now that you understand channels, you’re ready to start deploying live updates to real devices. The basic process is: 1. Install the Capgo SDK in your app 2. Configure the app to listen to your desired channel 3. Upload a build and assign it to that channel 4. Launch the app and wait for the update! For a more detailed walkthrough, see the [Deploying Live Updates](/docs/getting-started/deploy/) guide. Happy updating! ## Advanced Channel Usage: User Segmentation [Section titled “Advanced Channel Usage: User Segmentation”](#advanced-channel-usage-user-segmentation) Channels can be used for more than just development stages. They’re a powerful tool for user segmentation, enabling features like: * Feature flags for different user tiers * A/B testing * Gradual feature rollouts * Beta testing programs Learn how to implement these advanced use cases in our guide: [How to Segment Users by Plan and Channels for Feature Flags and A/B Testing](/blog/how-to-segment-users-by-plan-and-channels/). # Using Capgo in China > Learn how to configure Capgo Live Updates to work in China by using regional OST URLs for optimal performance and reliability. If you’re deploying your app to users in China, you’ll need to configure Capgo to use regional OST (Object Storage Technology) URLs to ensure reliable and fast updates. ## Why Use China-Specific URLs? [Section titled “Why Use China-Specific URLs?”](#why-use-china-specific-urls) Due to network infrastructure and regulations in China (the Great Firewall), direct connections to international servers can be slow or unreliable. Capgo provides dedicated OST URLs with data located in Hong Kong to minimize latency and ensure your users receive updates as quickly and reliably as possible. ## Configuration [Section titled “Configuration”](#configuration) To configure Capgo for China, you need to set three specific URLs in your Capacitor configuration file. These URLs point to Capgo’s Hong Kong-based infrastructure. 1. Open your `capacitor.config.ts` file 2. Add the following configuration to the `CapacitorUpdater` plugin section: ```typescript import { CapacitorConfig } from '@capacitor/cli'; const config: CapacitorConfig = { plugins: { CapacitorUpdater: { autoUpdate: true, updateUrl: 'https://updater.capgo.com.cn/updates', statsUrl: 'https://updater.capgo.com.cn/stats', channelUrl: 'https://updater.capgo.com.cn/channel_self', }, }, }; export default config; ``` 3. Rebuild your app to apply the changes: ```shell npm run build npx cap sync ``` ## Configuration Details [Section titled “Configuration Details”](#configuration-details) Here’s what each URL does: * **updateUrl**: `https://updater.capgo.com.cn/updates` - Used to check for and download available updates for your app * **statsUrl**: `https://updater.capgo.com.cn/stats` - Used to report analytics and usage statistics back to Capgo * **channelUrl**: `https://updater.capgo.com.cn/channel_self` - Used to retrieve channel configuration and determine which updates to apply Tip All three URLs must be configured together to ensure full functionality of the Capgo updater in China. ## Recommended Settings for China [Section titled “Recommended Settings for China”](#recommended-settings-for-china) Due to network performance limitations caused by the Great Firewall of China, we have specific recommendations for apps deployed in mainland China: ### Disable Direct Updates [Section titled “Disable Direct Updates”](#disable-direct-updates) We **strongly recommend disabling `directUpdate`** for apps in China. Network connectivity in China is less performant than in other regions, and direct updates (which apply immediately) can lead to a poor user experience if downloads are interrupted or slow. Instead, use the default update behavior where updates download in the background and apply when the app backgrounds or restarts. This provides a more reliable experience for your users. ```typescript const config: CapacitorConfig = { plugins: { CapacitorUpdater: { autoUpdate: true, directUpdate: false, // Recommended for China updateUrl: 'https://updater.capgo.com.cn/updates', statsUrl: 'https://updater.capgo.com.cn/stats', channelUrl: 'https://updater.capgo.com.cn/channel_self', }, }, }; ``` Caution While our Hong Kong-based infrastructure helps minimize latency and improve reliability, network performance to mainland China can still be affected by the Great Firewall. Disabling `directUpdate` helps ensure updates complete successfully without disrupting the user experience. ## Complete Configuration Example [Section titled “Complete Configuration Example”](#complete-configuration-example) Here’s a complete example with recommended settings for apps deployed in China: ```typescript import { CapacitorConfig } from '@capacitor/cli'; const config: CapacitorConfig = { appId: 'com.example.app', appName: 'My App', webDir: 'dist', plugins: { CapacitorUpdater: { autoUpdate: true, directUpdate: false, // Recommended: disable for better reliability in China updateUrl: 'https://updater.capgo.com.cn/updates', statsUrl: 'https://updater.capgo.com.cn/stats', channelUrl: 'https://updater.capgo.com.cn/channel_self', }, }, }; export default config; ``` ## Testing Your Configuration [Section titled “Testing Your Configuration”](#testing-your-configuration) After configuring the China-specific URLs, you can verify that updates are working correctly: 1. Upload a new bundle to Capgo: ```shell npx @capgo/cli@latest bundle upload --channel=production ``` 2. Install your app on a test device in China 3. Monitor the update process: ```shell npx @capgo/cli@latest app debug ``` 4. Check that updates are being downloaded from the China OST URLs Note The update behavior and timing remain the same as with standard Capgo configuration. See the [Update Behavior](/docs/live-updates/update-behavior/) documentation for details on how and when updates are applied. ## Multi-Region Deployment [Section titled “Multi-Region Deployment”](#multi-region-deployment) If your app serves users both inside and outside China, you can use the Chinese domain configuration for all users worldwide. The `updater.capgo.com.cn` domain is resolved globally thanks to Alibaba DNS infrastructure, making it accessible both inside China and everywhere else in the world. ### Using Chinese Domains Globally [Section titled “Using Chinese Domains Globally”](#using-chinese-domains-globally) The Chinese domain URLs work seamlessly for multi-region apps: ```typescript const config: CapacitorConfig = { plugins: { CapacitorUpdater: { autoUpdate: true, directUpdate: false, // Recommended for China users updateUrl: 'https://updater.capgo.com.cn/updates', statsUrl: 'https://updater.capgo.com.cn/stats', channelUrl: 'https://updater.capgo.com.cn/channel_self', }, }, }; ``` This single configuration will work for: * Users in mainland China (using Hong Kong-based infrastructure) * Users outside China (accessing the same infrastructure via Alibaba DNS) **Performance Considerations:** While the `.cn` domain is resolved globally through Alibaba DNS and works everywhere, it’s slightly less performant for users outside China compared to the standard domain (`api.capgo.app`), which is resolved directly by Cloudflare where our backend is hosted. However, DNS resolution is fast, so the performance difference is minimal and won’t significantly impact the user experience. Tip Using the `.cn` domain for all users simplifies your deployment and ensures consistent update behavior across all regions. You don’t need separate builds or environment-based configurations. The small performance trade-off outside China is typically worth the simplified deployment. ### Alternative: Region-Specific Configurations [Section titled “Alternative: Region-Specific Configurations”](#alternative-region-specific-configurations) If you prefer to optimize differently for each region, you can also consider: * Building separate app variants with different configurations * Using environment-based configuration to dynamically set the URLs * Creating different release channels for different regions If you need assistance with multi-region deployment strategies, please contact us at or join our [Discord community](https://discord.capgo.app) for help. ## Troubleshooting [Section titled “Troubleshooting”](#troubleshooting) If you experience issues with updates in China: 1. **Verify your configuration** - Double-check that all three URLs are correctly set in your `capacitor.config.ts` 2. **Check network connectivity** - Ensure your device can reach the `updater.capgo.com.cn` domain 3. **Review logs** - Use `npx @capgo/cli@latest app debug` to check for error messages 4. **Test updates** - Try uploading a new bundle and monitoring the download process 5. **Contact support** - If issues persist, reach out to us at or join our [Discord community](https://discord.capgo.app) for assistance Caution Make sure to use the `.cn` domain (`updater.capgo.com.cn`) and not the standard international domain when configuring for China. ## Next Steps [Section titled “Next Steps”](#next-steps) * Learn about [Update Behavior](/docs/live-updates/update-behavior/) to customize when updates are applied * Explore [Channels](/docs/live-updates/channels/) to manage different release tracks * Review [Encryption](/docs/live-updates/encryption/) to secure your updates # Compliance > Learn about Capgo's privacy practices, data collection, security compliance, and how we protect your users' information during live updates. Capgo is designed with privacy, security, and compliance in mind. This document explains what data is collected, how it’s used, and what measures are in place to protect your users’ privacy and ensure regulatory compliance when using Capgo’s live update service. ## Data Collection Overview [Section titled “Data Collection Overview”](#data-collection-overview) Capgo collects minimal data necessary to provide the live update service effectively. The data collection is focused on operational requirements rather than user tracking or analytics. ### What Data is Collected [Section titled “What Data is Collected”](#what-data-is-collected) Capgo collects only the data that is necessary to provide the live updates feature. When your app checks for updates or downloads new bundles, the following information is collected: * **App ID**: A unique identifier for your app that is used to associate the app with the correct account * **App Version Code**: The version code of the app that is used to determine which updates are compatible with the app * **App Version Name**: The version name of the app that is used for display purposes * **Platform**: The platform (iOS, Android, Electron) of the app that is used to determine which updates are compatible with the app * **Device ID**: A unique identifier for the device that is used to deliver updates to a specific device and for billing purposes. This identifier is a random string that is created when the app is started for the first time. **Starting from plugin version v5.10.0, v6.25.0 and v7.25.0**, the device ID now persists across app reinstalls (stored securely in Keychain on iOS, EncryptedSharedPreferences on Android, and Electron secure storage) to provide better device tracking while maintaining compliance with app store guidelines. Prior to these versions, the device ID was reset with every app installation * **Bundle ID**: The unique identifier for the bundle that is currently installed on the device * **Channel Name**: The name of the channel that is selected to receive updates * **OS Version**: The version of the operating system that is used to determine which updates are compatible with the device * **Plugin Version**: The version of the @capgo/capacitor-updater plugin that is used to deliver updates to the device **Additional Technical Data:** * Update check timestamps * Download success/failure status * Bundle installation status * Rollback events and reasons * IP address (for geolocation and CDN optimization) Note You can verify the data that is collected by inspecting the source code of the @capgo/capacitor-updater plugin, which is open-source and available on [GitHub](https://github.com/Cap-go/capacitor-updater). Capgo does not collect personally identifiable information (PII) such as names, email addresses, phone numbers, or persistent device identifiers that can be used to track individual users across apps. ### What Data is NOT Collected [Section titled “What Data is NOT Collected”](#what-data-is-not-collected) Capgo explicitly does not collect: * Personal user information or credentials * App usage analytics or user behavior data * Content from your app or user-generated data * Location data beyond general geographic region * Persistent device identifiers for tracking * Biometric or sensitive personal data ## Data Usage and Purpose [Section titled “Data Usage and Purpose”](#data-usage-and-purpose) The data collected by Capgo is used exclusively for: ### Service Operation [Section titled “Service Operation”](#service-operation) * Determining which updates are available for specific app versions * Optimizing content delivery through geographic CDN selection * Ensuring compatibility between updates and device capabilities * Managing update rollouts and channel assignments ### Service Improvement [Section titled “Service Improvement”](#service-improvement) * Monitoring update success rates and identifying issues * Optimizing download performance and reliability * Improving the overall update delivery system * Debugging and troubleshooting update failures ### Security and Integrity [Section titled “Security and Integrity”](#security-and-integrity) * Preventing abuse and ensuring service availability * Validating update authenticity and integrity * Protecting against malicious or corrupted updates * Maintaining service security and stability ## Data Storage and Retention [Section titled “Data Storage and Retention”](#data-storage-and-retention) ### Storage Location [Section titled “Storage Location”](#storage-location) * Update bundles and metadata are stored on secure cloud infrastructure * Data is distributed across multiple geographic regions for performance * All data transmission is encrypted using industry-standard protocols (HTTPS/TLS) ### Data Retention [Section titled “Data Retention”](#data-retention) * Update check logs are retained for operational purposes (typically 30-90 days) * Bundle files are retained as long as they’re assigned to active channels * Aggregated, non-personal metrics may be retained longer for service improvement * Personal data, if any, is deleted according to applicable data protection laws ### Data Security [Section titled “Data Security”](#data-security) * All data is encrypted in transit and at rest * Access to data is restricted to authorized personnel only * Regular security audits and monitoring are performed * Industry-standard security practices are followed * **SOC 2 Certification**: Capgo is currently SOC 2 Type II certified, ensuring the highest standards of security, availability, and confidentiality. View our compliance status at [trust.capgo.app](https://trust.capgo.app) * **Continuous Code Auditing**: Every commit is automatically audited by [SonarCloud](https://sonarcloud.io/summary/overall?id=Cap-go_capacitor-updater\&branch=main) for the [plugin](https://sonarcloud.io/summary/overall?id=Cap-go_capgo\&branch=main) and [backend](https://sonarcloud.io/summary/overall?id=Cap-go_capgo\&branch=main), ensuring code quality, security vulnerabilities detection, and maintainability * **Vulnerability Scanning**: Additional security scanning is performed by [Snyk](https://snyk.io/test/github/Cap-go/capgo) to detect and remediate security vulnerabilities in dependencies * **Infrastructure Security**: Our hosting infrastructure is continuously monitored and verified through [hosting security checks](https://hosting-checker.net/websites/api.capgo.app) * **AI-Powered Code Review**: Every pull request is reviewed by CodeRabbit AI to catch potential issues, security concerns, and maintain code quality standards ## Privacy Controls [Section titled “Privacy Controls”](#privacy-controls) ### For App Developers [Section titled “For App Developers”](#for-app-developers) As a Capgo user, you have control over: * **Channel Management**: Control which updates are distributed to which users * **Data Minimization**: Configure what device information is shared * **Geographic Controls**: Manage where your updates are distributed * **Retention Settings**: Control how long update data is retained ### For End Users [Section titled “For End Users”](#for-end-users) Your app users benefit from: * **Minimal Data Collection**: Only essential data for update delivery is collected * **No Tracking**: No cross-app or persistent user tracking * **Transparency**: This privacy policy explains exactly what data is collected * **Security**: All data transmission is encrypted and secure ## Compliance and Legal [Section titled “Compliance and Legal”](#compliance-and-legal) ### Data Protection Regulations [Section titled “Data Protection Regulations”](#data-protection-regulations) Capgo is designed to comply with major data protection regulations including: * **GDPR** (General Data Protection Regulation) * **CCPA** (California Consumer Privacy Act) * **COPPA** (Children’s Online Privacy Protection Act) * Other applicable regional privacy laws ### App Store Compliance [Section titled “App Store Compliance”](#app-store-compliance) Capgo strictly adheres to app store guidelines and policies: * **Apple App Store**: Complies with [App Store Review Guidelines](https://developer.apple.com/app-store/review/guidelines/) section 3.3.2, ensuring that live updates only modify the app’s behavior in ways that are consistent with the submitted app * **Google Play Store**: Follows [Google Play Developer Policy](https://play.google.com/about/developer-content-policy/) requirements for dynamic code loading and app updates * **Content Restrictions**: Live updates cannot introduce functionality that wasn’t present in the original app submission or violate platform-specific content policies * **Security Requirements**: All updates maintain the same security posture and permissions as the original app ### Your Responsibilities [Section titled “Your Responsibilities”](#your-responsibilities) As an app developer using Capgo, you should: * Include appropriate privacy disclosures in your app’s privacy policy * Inform users about the use of live update services * Ensure compliance with applicable laws in your jurisdiction * Implement appropriate consent mechanisms if required Tip **No Additional Privacy Implementation Required**: Capgo is designed to be privacy-compliant by default. You don’t need to implement any additional privacy controls or data handling mechanisms in your app code. The minimal data collection and privacy-by-design approach means that integrating Capgo typically doesn’t require changes to your existing privacy declarations or policies. ## Privacy by Design [Section titled “Privacy by Design”](#privacy-by-design) Capgo follows privacy-by-design principles: ### Data Minimization [Section titled “Data Minimization”](#data-minimization) * Only collect data that is absolutely necessary for service operation * Avoid collecting personal or sensitive information * Use aggregated and anonymized data where possible ### Purpose Limitation [Section titled “Purpose Limitation”](#purpose-limitation) * Use collected data only for the stated purposes * Do not repurpose data for unrelated activities * Maintain clear boundaries on data usage ### Transparency [Section titled “Transparency”](#transparency) * Provide clear information about data collection and usage * Make privacy practices easily accessible and understandable * Regularly update privacy documentation ## Contact and Questions [Section titled “Contact and Questions”](#contact-and-questions) If you have questions about Capgo’s privacy practices or need to report a privacy concern: * Review our full Privacy Policy at [capgo.app/privacy](https://capgo.app/privacy) * View our security and compliance status at [capgo.app/trust](https://capgo.app/trust) * Contact our privacy team through the support channels * Report any privacy-related issues through our security contact Tip Remember to update your own app’s privacy policy to reflect the use of Capgo’s live update service and any data collection that may occur as part of the update process. ## Best Practices for Privacy [Section titled “Best Practices for Privacy”](#best-practices-for-privacy) When implementing Capgo in your app: 1. **Be Transparent**: Inform users about the live update functionality 2. **Minimize Data**: Only enable data collection features you actually need 3. **Secure Implementation**: Follow security best practices in your integration 4. **Regular Reviews**: Periodically review your privacy practices and update policies 5. **User Control**: Consider providing users with options to control update behavior By following these practices and understanding Capgo’s privacy approach, you can provide your users with a secure, privacy-respecting live update experience. # Custom Storage > Learn how to use custom storage solutions with Capgo Live Updates, including external URLs, S3 integration, and bundle encryption for secure deployments. Capgo supports custom storage solutions for your app bundles, allowing you to host your updates on your own infrastructure or third-party storage services. This is particularly useful for organizations with specific security requirements, compliance needs, or existing storage infrastructure. ## Overview [Section titled “Overview”](#overview) Custom storage in Capgo works by uploading your bundle to an external location and providing Capgo with the URL to access it. The Capgo SDK will then download updates directly from your custom storage location instead of Capgo’s default cloud storage. Tip Custom storage is ideal for: * Organizations with strict data residency requirements * Teams with existing CDN or storage infrastructure * Applications requiring additional security layers * Cost optimization for large bundle sizes ## External URL Upload [Section titled “External URL Upload”](#external-url-upload) The simplest way to use custom storage is by uploading your bundle to any publicly accessible URL and providing that URL to Capgo. ### Basic External URL Upload [Section titled “Basic External URL Upload”](#basic-external-url-upload) ```shell npx @capgo/cli@latest bundle upload --external https://your-domain.com/bundles/v1.2.3.zip ``` This command tells Capgo to reference the bundle at the specified URL instead of uploading it to Capgo’s cloud storage. ### With Encryption [Section titled “With Encryption”](#with-encryption) For secure external storage, you can encrypt your bundle and provide the decryption keys: ```shell npx @capgo/cli@latest bundle upload --external https://your-domain.com/bundles/v1.2.3.zip --iv-session-key YOUR_IV_SESSION_KEY ``` ## S3 Integration [Section titled “S3 Integration”](#s3-integration) Capgo provides built-in support for Amazon S3 and S3-compatible storage services. The CLI can automatically upload your bundle to S3 and configure Capgo to use the S3 URL. ### S3 Upload Options [Section titled “S3 Upload Options”](#s3-upload-options) ```shell npx @capgo/cli@latest bundle upload \ --s3-region us-east-1 \ --s3-apikey YOUR_ACCESS_KEY \ --s3-apisecret YOUR_SECRET_KEY \ --s3-bucket-name your-bucket-name ``` ### Complete S3 Configuration [Section titled “Complete S3 Configuration”](#complete-s3-configuration) For S3-compatible services or custom endpoints: ```shell npx @capgo/cli@latest bundle upload \ --s3-region us-east-1 \ --s3-apikey YOUR_ACCESS_KEY \ --s3-apisecret YOUR_SECRET_KEY \ --s3-endpoint https://s3.your-provider.com \ --s3-bucket-name your-bucket-name \ --s3-port 443 \ --no-s3-ssl # Only if your endpoint doesn't support SSL ``` ### S3 Configuration Parameters [Section titled “S3 Configuration Parameters”](#s3-configuration-parameters) | Parameter | Description | Required | | ------------------ | ----------------------------- | -------- | | `--s3-region` | AWS region for your S3 bucket | Yes | | `--s3-apikey` | S3 access key ID | Yes | | `--s3-apisecret` | S3 secret access key | Yes | | `--s3-bucket-name` | Name of your S3 bucket | Yes | | `--s3-endpoint` | Custom S3 endpoint URL | No | | `--s3-port` | Port for S3 endpoint | No | | `--no-s3-ssl` | Disable SSL for S3 upload | No | ## Bundle Preparation and Encryption [Section titled “Bundle Preparation and Encryption”](#bundle-preparation-and-encryption) When using custom storage, especially with encryption, you need to prepare your bundles properly. This involves creating a zip file and optionally encrypting it. ### Step 1: Create a Zip Bundle [Section titled “Step 1: Create a Zip Bundle”](#step-1-create-a-zip-bundle) First, create a zip file of your app bundle: ```shell npx @capgo/cli@latest bundle zip com.example.app --path ./dist ``` The zip command will return the checksum of the zip file. You can use this checksum to encrypt the zip file if needed. Use the `--json` option to get structured output including the checksum. #### Zip Command Options [Section titled “Zip Command Options”](#zip-command-options) ```shell npx @capgo/cli@latest bundle zip [appId] \ --path ./dist \ --bundle 1.2.3 \ --name myapp-v1.2.3 \ --json \ --no-code-check \ --key-v2 \ --package-json ../../package.json,./package.json ``` | Option | Description | | ----------------- | -------------------------------------------------------------------- | | `--path` | Path to the folder to zip (defaults to webDir from capacitor.config) | | `--bundle` | Bundle version number to name the zip file | | `--name` | Custom name for the zip file | | `--json` | Output results in JSON format (includes checksum) | | `--no-code-check` | Skip checking for notifyAppReady() call and index file | | `--key-v2` | Use encryption v2 | | `--package-json` | Paths to package.json files for monorepos (comma separated) | ### Step 2: Encrypt the Bundle (Optional) [Section titled “Step 2: Encrypt the Bundle (Optional)”](#step-2-encrypt-the-bundle-optional) For enhanced security, encrypt your zip bundle before uploading: ```shell # Using default local key npx @capgo/cli@latest bundle encrypt ./myapp.zip CHECKSUM # Using custom key file npx @capgo/cli@latest bundle encrypt ./myapp.zip CHECKSUM --key ./path/to/.capgo_key_v2 # Using key data directly npx @capgo/cli@latest bundle encrypt ./myapp.zip CHECKSUM --key-data "PRIVATE_KEY_CONTENT" ``` The `CHECKSUM` parameter is required and should be the checksum of your zip file. You can get the checksum from the zip command output (use `--json` option for structured output). By default, the encrypt command will use your local private signing key. You can specify a custom key using the `--key` or `--key-data` options. The encrypt command will return the `ivSessionKey` needed for upload or decryption. #### Encryption Command Options [Section titled “Encryption Command Options”](#encryption-command-options) | Option | Description | | ------------ | ------------------------------------------------------------------------- | | `zipPath` | Path to the zip file to encrypt (required) | | `checksum` | Checksum of the zip file (required) - get it from zip command | | `--key` | Custom path for private signing key (optional, uses local key by default) | | `--key-data` | Private signing key data directly (optional) | | `--json` | Output results in JSON format | Caution The encrypt command will output an `ivSessionKey` that you’ll need to provide when uploading with the `--iv-session-key` option. ## Complete Workflow Examples [Section titled “Complete Workflow Examples”](#complete-workflow-examples) ### Example 1: External URL with Encryption [Section titled “Example 1: External URL with Encryption”](#example-1-external-url-with-encryption) 1. **Build your app:** ```shell npm run build ``` 2. **Create a zip bundle:** ```shell npx @capgo/cli@latest bundle zip com.example.app --path ./dist --bundle 1.2.3 ``` Note the checksum returned by this command. 3. **Encrypt the bundle:** ```shell npx @capgo/cli@latest bundle encrypt ./com.example.app-1.2.3.zip CHECKSUM_FROM_STEP_2 ``` Note the `ivSessionKey` from the output. 4. **Upload to your storage:** Upload the encrypted zip file to your hosting service. 5. **Register with Capgo:** ```shell npx @capgo/cli@latest bundle upload \ --external https://your-cdn.com/bundles/com.example.app-1.2.3.zip \ --iv-session-key IV_SESSION_KEY_FROM_STEP_3 ``` ### Example 2: Direct S3 Upload [Section titled “Example 2: Direct S3 Upload”](#example-2-direct-s3-upload) 1. **Build your app:** ```shell npm run build ``` 2. **Upload directly to S3:** ```shell npx @capgo/cli@latest bundle upload \ --s3-region us-west-2 \ --s3-apikey YOUR_ACCESS_KEY \ --s3-apisecret YOUR_SECRET_KEY \ --s3-bucket-name your-app-bundles \ --channel Production ``` ### Example 3: S3 with Encryption [Section titled “Example 3: S3 with Encryption”](#example-3-s3-with-encryption) 1. **Build and zip:** ```shell npm run build npx @capgo/cli@latest bundle zip com.example.app --path ./dist --key-v2 ``` 2. **Encrypt the bundle:** ```shell npx @capgo/cli@latest bundle encrypt ./com.example.app.zip CHECKSUM ``` 3. **Upload to S3 with encryption:** ```shell npx @capgo/cli@latest bundle upload \ --s3-region us-west-2 \ --s3-apikey YOUR_ACCESS_KEY \ --s3-apisecret YOUR_SECRET_KEY \ --s3-bucket-name your-app-bundles \ --iv-session-key IV_SESSION_KEY_FROM_STEP_2 \ --channel Production ``` ## Security Considerations [Section titled “Security Considerations”](#security-considerations) When using custom storage, consider these security best practices: ### Access Control [Section titled “Access Control”](#access-control) * Ensure your storage URLs are accessible to your app users but not publicly discoverable * Use signed URLs or token-based authentication when possible * Implement proper CORS headers for web-based apps ### Encryption [Section titled “Encryption”](#encryption) * Always encrypt sensitive bundles using the Capgo encryption tools * Store encryption keys securely and rotate them regularly * Use HTTPS for all bundle URLs (required for mobile and Electron apps) ### Monitoring [Section titled “Monitoring”](#monitoring) * Monitor access logs to detect unusual download patterns * Set up alerts for failed bundle downloads * Regularly audit your storage permissions ## Troubleshooting [Section titled “Troubleshooting”](#troubleshooting) ### Common Issues [Section titled “Common Issues”](#common-issues) **Bundle not downloading:** * Verify the URL is publicly accessible and uses HTTPS (required for mobile and Electron apps) * Check CORS headers for web apps * Ensure the bundle format is correct **Encryption errors:** * Verify the `ivSessionKey` matches the encrypted bundle * Check that the bundle was encrypted with the correct key * Ensure encryption v2 is used for new bundles **S3 upload failures:** * Verify your S3 credentials and permissions * Check bucket policies and CORS configuration * Ensure the specified region is correct ### Debug Commands [Section titled “Debug Commands”](#debug-commands) Check bundle status: ```shell npx @capgo/cli@latest app debug ``` Verify bundle integrity: ```shell npx @capgo/cli@latest bundle list ``` ## Next Steps [Section titled “Next Steps”](#next-steps) * Learn about [Channels](/docs/live-updates/channels/) to manage different deployment environments * Explore [Update Behavior](/docs/live-updates/update-behavior/) to customize how updates are applied * Set up [CI/CD Integration](/docs/getting-started/cicd-integration/) to automate your custom storage workflow # Delta updates > Learn how Capgo's Delta (manifest) updates optimize data transfer by only sending changed files, enhancing performance on slower networks. Capgo’s Live Update system can deliver updates faster and more efficiently by only sending the changed files, rather than the entire JS bundle. This is especially beneficial for users on slower or metered network connections, as it minimizes the amount of data that needs to be downloaded. A second benefit is when the app have large assets who change rarely, like images or videos, compare to zipped JS files it will be downloaded only once. ## How Delta (Manifest) Updates Work [Section titled “How Delta (Manifest) Updates Work”](#how-delta-manifest-updates-work) Delta (manifest) updates in Capgo are handled by the Capgo plugin installed in your app. When you upload a new version of your app using the `--delta` flag, Capgo does the following: 1. Each file in your build is uploaded individually 2. Checksums are generated for each file 3. A new json manifest is created, listing all files and their checksums 4. This manifest is uploaded to the Capgo database When a device running your app checks for an update, the Capgo plugin receives the new manifest from the server. It compares this manifest to the one it currently has, identifying which files have changed based on the checksums and file paths. The plugin then downloads only the changed files, rather than the entire JS bundle. It reconstructs the new version of the app by combining these downloaded files with the unchanged files it already has. Manifest In case of Delta (manifest) updates, the device stores all downloaded files in a common cache. Capgo never cleans it, but the OS can at any time. ## Enabling Delta (Manifest) Updates [Section titled “Enabling Delta (Manifest) Updates”](#enabling-delta-manifest-updates) To enable Delta (manifest) updates for your Capgo app, simply use the `--delta` flag when uploading a new version: ```shell npx @capgo/cli@latest bundle upload --delta ``` If `directUpdate` is enabled in your `capacitor.config`, the CLI detects it. In non-interactive environments it sends Delta (manifest) updates automatically, and in interactive environments it prompts you to confirm before uploading. Use `--no-delta` to force a full bundle upload. ## Enforcing Delta (Manifest) Updates [Section titled “Enforcing Delta (Manifest) Updates”](#enforcing-delta-manifest-updates) If you want to ensure that all uploads are Delta (manifest) updates and prevent any accidental full bundle uploads, you can use the `--delta-only` flag: ```shell npx @capgo/cli@latest bundle upload --delta-only ``` When `--delta-only` is used, Capgo will only upload individual files and generate a manifest. Any device that does not support Delta (manifest) updates will not be able to download the update. You might want to use `--delta-only` if: * You always want to use Delta (manifest) updates and never want to allow full bundle uploads * You’re setting up a CI/CD pipeline and want to ensure all automated uploads are Delta (manifest) * Your app is large and bandwidth is constrained, so you need to minimize upload/download sizes If you need to do a full bundle upload while `--delta-only` is set, simply run the upload command without `--delta-only`. This will override the setting for that single upload, allowing you to push a complete bundle when needed. ## Troubleshooting [Section titled “Troubleshooting”](#troubleshooting) If Delta (manifest) updates don’t seem to be working (i.e. devices are always downloading the full JS bundle even for small changes), double check that: * You’re using the `--delta` flag every time you upload a new version * If using `--delta-only`, make sure you haven’t accidentally omitted the `--delta` flag * Your device is running the latest version of the Capgo plugin * Your device has a stable network connection and can reach the Capgo servers You can also use the Capgo webapp to check the details of your last upload: 1. Go to the [webapp](https://app.capgo.io) 2. Click on your app 3. Click on the bundles number of the stats bar. 4. Select the last bundle 5. Check the `Partial` field ![bundle type](/bundle_type.webp) If you continue to have trouble, please reach out to Capgo support for further assistance. They can check the server logs to confirm that your Delta (manifest) uploads are being processed correctly and that devices are receiving the updated manifests. That’s it! The `--delta` flag tells Capgo to perform the individual file uploads and manifest generation needed for Delta (manifest) updates. Note that you need to use `--delta` every time you upload a new version that you want to be delivered as a Delta (manifest) update. If you omit the flag, Capgo will upload the entire JS bundle as a single file, and devices will download the whole bundle even if only a small part has changed. # Encryption > Learn how Capgo's end-to-end encryption secures your app bundles during transmission and storage, protecting your code and user data. Capgo provides robust end-to-end encryption for your app bundles, ensuring that your JavaScript code and assets are protected during transmission and storage. This encryption system is designed to give you complete control over your app’s security while maintaining the convenience of live updates. ## Overview [Section titled “Overview”](#overview) Capgo’s encryption system uses industry-standard cryptographic methods to protect your bundles from unauthorized access. When encryption is enabled, your bundles are encrypted before leaving your development environment and remain encrypted until they’re decrypted by your app on the user’s device. **What Encryption Actually Protects**: Unlike OTA systems that only sign updates, Capgo encrypts the uploaded bundle before storage and delivery. This protects the bundle contents from casual access in storage or transit and ensures only someone with your private key can produce a valid encrypted update. It does **not** make shipped web assets impossible to reverse engineer: the public key used by the client to decrypt updates is distributed in the app, so a determined attacker can still extract it and inspect bundle contents with enough effort. When You Need Encryption If you upload a bundle without encryption, treat it as a public asset. Private channels limit which devices receive an update, but they do not make the uploaded bundle confidential. Encryption is useful when you want better protection in storage and transit and when you want only holders of the private key to be able to publish valid encrypted updates. It does not guarantee that shipped JavaScript, HTML, or CSS can never be inspected. Threat Model Capgo encryption protects against bundle disclosure by Capgo, storage providers, CDNs, or anyone who only sees the encrypted delivery artifact. It also prevents third parties from generating valid encrypted updates without your private key. Because the public key is embedded in the distributed app so the client can decrypt updates, someone who has your app binary and enough motivation can still recover the key material needed to inspect the bundle. Tip Encryption is particularly important for: * Apps handling sensitive data or business logic * Enterprise applications with compliance requirements * Apps deployed in regulated industries * Organizations with strict security policies ## How Encryption Works [Section titled “How Encryption Works”](#how-encryption-works) Capgo uses a hybrid encryption approach that combines RSA and AES encryption for optimal security and performance: ![Capgo Encryption Flow](/encryption_flow.webp) ### 1. Key Generation [Section titled “1. Key Generation”](#1-key-generation) * **Private Key**: Generated and stored securely in your development environment (used for encryption) * **Public Key**: Derived from your private key and stored in your app’s Capacitor config (used for decryption) * **Session Keys**: Random AES keys generated for each bundle upload ### 2. Encryption Process [Section titled “2. Encryption Process”](#2-encryption-process) 1. A random AES session key is generated for each bundle upload 2. Your bundle is encrypted using the AES session key 3. The bundle checksum is calculated 4. Both the AES session key and checksum are encrypted together using your RSA private key (creating the “signature”) 5. The encrypted bundle and encrypted signature are stored The checksum is encrypted alongside the AES key to prevent tampering. Since only your RSA private key can create this signature, and only the corresponding public key can decrypt it, this ensures that both the AES session key and the expected checksum are authentic and haven’t been modified by an attacker. ### 3. Decryption Process [Section titled “3. Decryption Process”](#3-decryption-process) 1. Your app downloads the encrypted bundle and encrypted signature 2. The Capgo SDK uses your RSA public key (stored in the app) to decrypt the signature 3. This reveals the AES session key and the original checksum 4. The AES session key is used to decrypt the bundle 5. A checksum of the decrypted bundle is calculated and compared with the original checksum for integrity verification This process ensures that even if an attacker intercepts the encrypted bundle, they cannot modify the AES session key or provide a fake checksum, because they would need your private key to create a valid signature that the public key can decrypt. Tip RSA cannot encrypt large amounts of data efficiently, so AES is used for the actual bundle encryption while RSA secures the AES key and provides integrity verification through checksum signing. ## Capgo vs Other Platforms [Section titled “Capgo vs Other Platforms”](#capgo-vs-other-platforms) | Feature | Capgo | Other OTA Platforms | | ------------------- | ---------------------------------------------------------------------------------------------------- | ----------------------------- | | **Bundle Content** | Encrypted in storage/transit; still inspectable by a determined reverse engineer with the app binary | Publicly readable | | **Security Method** | True end-to-end encryption | Code signing only | | **Privacy Level** | Strong delivery/storage protection; not anti-reverse-engineering | Platform can access your code | | **Protection** | Content + integrity + authenticity | Integrity + authenticity only | **Why This Matters:** * **Code signing** only verifies that updates haven’t been tampered with and come from the right source * **Capgo encryption** protects the bundle while it is stored and delivered and makes forged encrypted updates much harder because the attacker would need your private key * **Reverse engineering is still possible** after the app ships, because the client contains the public key needed to decrypt and load the update ## Encryption Methods [Section titled “Encryption Methods”](#encryption-methods) Capgo uses Encryption V2 as the standard encryption method: ### Encryption V2 (Current Standard) [Section titled “Encryption V2 (Current Standard)”](#encryption-v2-current-standard) * Uses RSA-4096 for enhanced security * AES-256-GCM for authenticated encryption * Provides integrity verification * Better performance and security ### Encryption V1 (Deprecated) [Section titled “Encryption V1 (Deprecated)”](#encryption-v1-deprecated) * Uses RSA-2048 for key encryption * AES-256-CBC for bundle encryption * **No longer available in the current CLI** * Legacy apps using V1 must migrate to V2 Danger Encryption V1 is no longer supported in the current Capgo CLI. If you’re using V1 encryption, you must migrate to V2. See the [migration guide](/docs/cli/migrations/encryption/) for detailed instructions. ## Setting Up Encryption [Section titled “Setting Up Encryption”](#setting-up-encryption) ### Step 1: Generate Encryption Keys [Section titled “Step 1: Generate Encryption Keys”](#step-1-generate-encryption-keys) First, generate your encryption keys using the Capgo CLI: ```shell # Generate new encryption keys (creates files in current directory) npx @capgo/cli@latest key create ``` This creates: * `.capgo_key_v2`: Your private key (keep this secure!) * `.capgo_key_v2.pub`: Your public key (used by your app) These files are created in the current directory where you run the command. Caution **Important Storage Notes:** * **Private Key (`.capgo_key_v2`)**: Never commit this to version control. This file should be kept secure and used only for encryption during bundle uploads. * **Public Key (`.capgo_key_v2.pub`)**: This is safe to commit to version control as it’s a backup of your public key. * **File Location**: Keys are created in the current directory where you run the `key create` command. * **Public Key in Config**: You must run `key save` to store the public key in your Capacitor config for the mobile app to use. For production use, store the private key securely (environment variables, key management services) and remove it from your local project after setup. ### Step 2: Save Your Public Key to Capacitor Config (Required) [Section titled “Step 2: Save Your Public Key to Capacitor Config (Required)”](#step-2-save-your-public-key-to-capacitor-config-required) You **must** save your public key to the Capacitor config so your mobile app can decrypt bundles: ```shell # Save public key from file to Capacitor config (required) npx @capgo/cli@latest key save --key ./.capgo_key_v2.pub # Or save public key data directly npx @capgo/cli@latest key save --key-data "$CAPGO_PUBLIC_KEY" ``` ### Step 3: Sync Capacitor Platform (Required) [Section titled “Step 3: Sync Capacitor Platform (Required)”](#step-3-sync-capacitor-platform-required) After saving the public key, you **must** sync the Capacitor platform to copy the updated config to the native layer: ```shell # Sync the platform to copy config to native npx cap sync ``` Caution **Required Steps**: 1. The `key save` command stores the public key in your Capacitor config 2. `npx cap sync` copies this config to the native layer where the mobile app can access it 3. Without both steps, your app won’t be able to decrypt encrypted updates ## Encrypting Bundles [Section titled “Encrypting Bundles”](#encrypting-bundles) ### Method 1: Encrypt During Upload [Section titled “Method 1: Encrypt During Upload”](#method-1-encrypt-during-upload) The simplest way is to encrypt during the upload process: ```shell # Upload with automatic encryption npx @capgo/cli@latest bundle upload --key-v2 # For external storage, you must encrypt first (see Manual Encryption Workflow below) ``` ### Method 2: Manual Encryption Workflow [Section titled “Method 2: Manual Encryption Workflow”](#method-2-manual-encryption-workflow) For more control, you can manually encrypt bundles: 1. **Create a zip bundle:** ```shell npx @capgo/cli@latest bundle zip com.example.app --path ./dist --key-v2 ``` 2. **Encrypt the bundle:** ```shell npx @capgo/cli@latest bundle encrypt ./com.example.app.zip CHECKSUM_FROM_STEP_1 ``` 3. **Upload to your storage (e.g., S3) and register with Capgo:** ```shell # First upload the encrypted bundle to your storage (e.g., AWS S3) aws s3 cp ./encrypted-bundle.zip s3://your-bucket/encrypted-bundle.zip # Then register with Capgo using the external URL npx @capgo/cli@latest bundle upload --external https://your-storage.com/encrypted-bundle.zip --iv-session-key IV_SESSION_KEY_FROM_STEP_2 ``` ## Key Management [Section titled “Key Management”](#key-management) ### Storing Keys Securely [Section titled “Storing Keys Securely”](#storing-keys-securely) **Private Key Options:** 1. **File-based (local development):** ```shell # Key stored as .capgo_key_v2 file in project root npx @capgo/cli@latest bundle upload --key-v2 ``` 2. **Environment variable (CI/CD):** ```shell # Store in environment variable for CI export CAPGO_PRIVATE_KEY="$(cat .capgo_key_v2)" npx @capgo/cli@latest bundle upload --key-data-v2 "$CAPGO_PRIVATE_KEY" ``` **Public Key Setup (Required):** ```shell # Must save public key to Capacitor config for mobile app npx @capgo/cli@latest key save --key ./.capgo_key_v2.pub ``` **Production Environment:** * Store private keys in secure key management services (AWS KMS, Azure Key Vault, etc.) * Use CI/CD secret management for private keys * Never commit private keys to version control **Key Usage:** * **Private Key**: Used by CLI for encryption during bundle upload (keep secure) * **Public Key**: Stored in app configuration for decryption on device (safe to commit) ### Key Rotation [Section titled “Key Rotation”](#key-rotation) Regularly rotate your encryption keys for enhanced security: 1. **Generate new keys:** ```shell # Navigate to desired directory first, then create keys mkdir ./new-keys && cd ./new-keys npx @capgo/cli@latest key create ``` 2. **Save the new public key to Capacitor config:** ```shell npx @capgo/cli@latest key save --key ./new-keys/.capgo_key_v2.pub ``` 3. **Update your app configuration** with the new public key 4. **Deploy the updated app** before uploading encrypted bundles with the new key ## Security Best Practices [Section titled “Security Best Practices”](#security-best-practices) ### Key Security [Section titled “Key Security”](#key-security) * **Never share private keys** between environments or team members * **Use different keys** for different environments (dev, staging, production) * **Rotate keys regularly** (recommended: every 6-12 months) * **Store keys securely** using proper key management systems ### Bundle Security [Section titled “Bundle Security”](#bundle-security) * **Always verify** bundle integrity after decryption * **Monitor** for unusual download patterns or failures * **Use HTTPS** for all bundle URLs (required for mobile apps) * **Implement** proper error handling for decryption failures ### Access Control [Section titled “Access Control”](#access-control) * **Limit access** to encryption keys to authorized personnel only * **Use role-based access** for key management operations * **Audit** key usage and access regularly * **Implement** proper backup and recovery procedures ## Troubleshooting Encryption [Section titled “Troubleshooting Encryption”](#troubleshooting-encryption) ### Common Issues [Section titled “Common Issues”](#common-issues) **Decryption failures:** * Verify the private key matches the public key used for encryption * Check that the `ivSessionKey` is correct * Ensure you’re using Encryption V2 (V1 is no longer supported) **Key-related errors:** * Confirm the private key format is correct (PEM format) * Verify the key hasn’t been corrupted during storage/transfer * Check that the key has proper permissions in your app configuration **Performance issues:** * Large bundles may take longer to encrypt/decrypt * Consider using Delta (manifest) updates to reduce bundle sizes * Monitor device performance during decryption ### Debug Commands [Section titled “Debug Commands”](#debug-commands) Check encryption status: ```shell npx @capgo/cli@latest app debug ``` Test encryption/decryption workflow: ```shell # Test the complete workflow: zip → encrypt → decrypt → unzip npx @capgo/cli@latest bundle zip com.example.app --key-v2 npx @capgo/cli@latest bundle encrypt ./com.example.app.zip CHECKSUM --json npx @capgo/cli@latest bundle decrypt ./encrypted-bundle.zip IV_SESSION_KEY ``` ## Compliance and Standards [Section titled “Compliance and Standards”](#compliance-and-standards) Capgo’s encryption implementation follows industry standards: * **AES-256**: FIPS 140-2 approved encryption algorithm * **RSA-4096**: Strong asymmetric encryption for key protection * **GCM Mode**: Provides both confidentiality and authenticity * **Secure Random**: Cryptographically secure random number generation This makes Capgo suitable for applications requiring compliance with: * GDPR (General Data Protection Regulation) * HIPAA (Health Insurance Portability and Accountability Act) * SOC 2 (Service Organization Control 2) * ISO 27001 (Information Security Management) ## Performance Considerations [Section titled “Performance Considerations”](#performance-considerations) ### Encryption Overhead [Section titled “Encryption Overhead”](#encryption-overhead) * **Bundle size**: Encrypted bundles are slightly larger (\~1-2% overhead) * **Processing time**: Encryption/decryption adds minimal latency * **Memory usage**: Temporary increase during encryption/decryption operations ### Optimization Tips [Section titled “Optimization Tips”](#optimization-tips) * Use Delta (manifest) updates to minimize encrypted data transfer * Optimize your bundle size by converting images to WebP format * Minimize JavaScript and CSS files before bundling * Remove unused dependencies and code * Monitor device performance on older/slower devices ## Next Steps [Section titled “Next Steps”](#next-steps) * Learn about [Custom Storage](/docs/live-updates/custom-storage/) to use encryption with your own infrastructure * Explore [Channels](/docs/live-updates/channels/) to manage encrypted bundles across environments * Set up [CI/CD Integration](/docs/getting-started/cicd-integration/) to automate encrypted deployments # Features > Complete reference of all Capgo Live Update capabilities, from core update system to advanced deployment controls, analytics, and team collaboration features. This page provides a comprehensive overview of all features available in Capgo Live Updates. Each feature includes a brief description and links to detailed documentation. ## Core Update System [Section titled “Core Update System”](#core-update-system) ### Over-the-Air (OTA) Updates [Section titled “Over-the-Air (OTA) Updates”](#over-the-air-ota-updates) Deploy JavaScript, HTML, CSS, and asset updates directly to users without app store approval. Updates are downloaded in the background and applied on next app restart. **Key capabilities:** * Background downloads * Automatic installation * No user interruption * Cross-platform support (iOS, Android, Electron) [Learn more about update behavior →](/docs/live-updates/update-behavior/) *** ### Delta Updates (Differential Updates) [Section titled “Delta Updates (Differential Updates)”](#delta-updates-differential-updates) Only download files that have changed between versions, reducing bandwidth usage by up to 95% and speeding up update delivery. **Key capabilities:** * Automatic file-level diffing * Checksum-based verification * Manifest comparison * Intelligent fallback to full updates when needed [Learn more about delta updates →](/docs/live-updates/differentials/) *** ### Automatic Rollback [Section titled “Automatic Rollback”](#automatic-rollback) If an update fails to load or causes crashes, the system automatically reverts to the last known working version. **Key capabilities:** * Crash detection * Timeout detection * Automatic reversion * No user intervention required [Learn more about rollbacks →](/docs/live-updates/rollbacks/) *** ### Checksum Validation & Fallback [Section titled “Checksum Validation & Fallback”](#checksum-validation--fallback) Verifies bundle integrity via checksums and automatically falls back to the last known working version if corruption is detected. **Key capabilities:** * Checksum validation on download * Corruption detection * Automatic fallback to last working bundle * Manual recovery tools available *** ### Breaking Update Detection [Section titled “Breaking Update Detection”](#breaking-update-detection) Prevents incompatible updates from being applied to devices running older native code versions. **Key capabilities:** * Native version compatibility checking * Plugin dependency validation * Automatic blocking of incompatible updates * Clear error messaging [Learn more about version targeting →](/docs/live-updates/version-targeting/) *** ## Deployment Control [Section titled “Deployment Control”](#deployment-control) ### Channel System [Section titled “Channel System”](#channel-system) Organize and manage updates across different environments and user segments with flexible channel configurations. **Key capabilities:** * Unlimited custom channels (production, staging, beta, etc.) * Per-channel bundle assignments * Channel-specific targeting rules * Device self-assignment * Channel override per device [Learn more about channels →](/docs/live-updates/channels/) *** ### Device Targeting [Section titled “Device Targeting”](#device-targeting) Target specific devices, versions, or user segments for phased rollouts and controlled deployments. **Key capabilities:** * Version-based targeting * Device-specific overrides * Platform filtering (iOS, Android, Electron) * Custom metadata filtering * Emulator/dev build blocking *** ### Channel Policies [Section titled “Channel Policies”](#channel-policies) Configure rules and restrictions for how updates are delivered on each channel. **Key capabilities:** * Disable auto-updates * Block major version updates * Disable updates on emulators * Disable updates in development builds * Platform-specific policies (iOS-only, Android-only, Electron-only) [Learn more about channel policies →](/docs/live-updates/channels/#channel-policies) *** ## Developer Tools [Section titled “Developer Tools”](#developer-tools) ### Bundle Preview [Section titled “Bundle Preview”](#bundle-preview) Preview bundles in a live web environment before deploying to devices, accessible from the web dashboard. **Location:** Web Dashboard → App → Bundle → Preview tab *** ### Live Debugging [Section titled “Live Debugging”](#live-debugging) Real-time monitoring of update events for specific devices via CLI, showing check, download, install, and error events. **Usage:** ```bash npx @capgo/cli app debug [appId] ``` **Shows:** * Update checks * Download progress * Installation status * Error messages * Policy blocks *** ### Bundle Manifest Viewer [Section titled “Bundle Manifest Viewer”](#bundle-manifest-viewer) Inspect the complete manifest of any bundle including file list, checksums, and metadata. **Location:** Web Dashboard → App → Bundle → Manifest tab **Shows:** * File list with checksums * Bundle metadata * Native version compatibility * Plugin dependencies *** ### Native Plugin Dependencies [Section titled “Native Plugin Dependencies”](#native-plugin-dependencies) View all native Capacitor plugins included in each bundle to track dependency changes across versions. **Location:** Web Dashboard → App → Bundle → Dependencies tab **Shows:** * Plugin names and versions * Dependency additions/removals * Compatibility warnings *** ### CLI Integration [Section titled “CLI Integration”](#cli-integration) Comprehensive command-line interface for automated deployments and CI/CD integration. **Key commands:** * `bundle upload` - Upload new bundles * `bundle list` - List all bundles * `bundle delete` - Delete bundles * `bundle cleanup` - Clean up old bundles * `channel set` - Configure channels * `app debug` - Live debugging [View full CLI reference →](/docs/cli/commands/) *** ### Bundle Encryption [Section titled “Bundle Encryption”](#bundle-encryption) End-to-end encryption for bundles with AES-256 encryption, protecting your code in transit and at rest. **Key capabilities:** * RSA key pair generation * AES-256 bundle encryption * Code signature verification * Encryption key management [Learn more about encryption →](/docs/live-updates/encryption/) *** ### Bundle Cleanup & Retention [Section titled “Bundle Cleanup & Retention”](#bundle-cleanup--retention) Automatically clean up old bundles based on retention policies to manage storage usage. **Key capabilities:** * Configurable retention count * Automatic cleanup via CLI * Scheduled cleanup jobs * Storage usage tracking **Usage:** ```bash npx @capgo/cli bundle cleanup --keep=10 ``` *** ## Analytics & Monitoring [Section titled “Analytics & Monitoring”](#analytics--monitoring) ### Update Statistics [Section titled “Update Statistics”](#update-statistics) Track update adoption rates, success rates, and deployment progress across your user base. **Metrics available:** * Download success rate * Installation success rate * Error rates by type * Update adoption over time * Version distribution **Location:** Web Dashboard → App → Statistics *** ### Device Logs [Section titled “Device Logs”](#device-logs) Per-device event logs showing complete update lifecycle from check to installation. **Event types:** * Update checks * Download start/complete/fail * Install start/complete/fail * Rollback events * Policy blocks **Location:** * Web Dashboard → App → Device → Logs * Web Dashboard → App → Logs (all devices) [Learn more about logs →](/docs/webapp/logs/) *** ### Bundle Usage Analytics [Section titled “Bundle Usage Analytics”](#bundle-usage-analytics) Detailed analytics on which bundles are active, download counts, and storage usage. **Metrics:** * Active installations per bundle * Download counts * Storage usage per bundle * Bandwidth usage *** ### Channel Statistics [Section titled “Channel Statistics”](#channel-statistics) Track performance and adoption metrics per channel. **Metrics:** * Devices per channel * Update success rates per channel * Deployment history * Error rates by channel **Location:** Web Dashboard → App → Channel → Statistics *** ### Deployment History [Section titled “Deployment History”](#deployment-history) Complete audit trail of all bundle deployments, channel assignments, and configuration changes. **Tracked events:** * Bundle uploads * Channel assignments * Policy changes * Device overrides **Location:** Web Dashboard → App → Channel → History *** ## Security & Compliance [Section titled “Security & Compliance”](#security--compliance) ### End-to-End Encryption [Section titled “End-to-End Encryption”](#end-to-end-encryption) Encrypt bundles at rest and in transit with industry-standard AES-256 encryption. [Learn more about encryption →](/docs/live-updates/encryption/) *** ### Code Signing [Section titled “Code Signing”](#code-signing) Verify bundle integrity with cryptographic signatures to prevent tampering. *** ### SOC 2 Type II Compliance [Section titled “SOC 2 Type II Compliance”](#soc-2-type-ii-compliance) Infrastructure and processes certified to SOC 2 Type II standards for enterprise security. *** ### App Store Compliance [Section titled “App Store Compliance”](#app-store-compliance) Fully compliant with Apple App Store and Google Play Store policies for OTA updates. [Learn more about compliance →](/docs/live-updates/compliance/) *** ### 2FA Enforcement (Organization-level) [Section titled “2FA Enforcement (Organization-level)”](#2fa-enforcement-organization-level) Require two-factor authentication for all organization members to access the dashboard and API. **Location:** Web Dashboard → Organization → Security [Learn more about 2FA →](/docs/webapp/2fa-enforcement/) *** ### Encrypted Bundles Enforcement [Section titled “Encrypted Bundles Enforcement”](#encrypted-bundles-enforcement) Require all bundles to be encrypted at the organization level. **Location:** Web Dashboard → Organization → Security *** ## Team Collaboration [Section titled “Team Collaboration”](#team-collaboration) ### Role-Based Access Control (RBAC) [Section titled “Role-Based Access Control (RBAC)”](#role-based-access-control-rbac) Granular permissions for organization and app-level access control. **Organization roles:** * `org_super_admin` - Full organization control * `org_admin` - Organization administration (no billing/deletion) * `org_billing_admin` - Billing-only access * `org_member` - Read-only organization access **App roles:** * `app_admin` - Full control of one app * `app_developer` - Upload bundles, manage devices * `app_uploader` - Upload bundles only * `app_reader` - Read-only access **Location:** * Web Dashboard → Organization → Members * Web Dashboard → App → Access [Learn more about RBAC →](/docs/webapp/organization-system/#roles-overview) *** ### Audit Logs [Section titled “Audit Logs”](#audit-logs) Complete audit trail of all organization and app activities for compliance and security. **Logged events:** * User actions (login, logout, permission changes) * Bundle operations (upload, delete, assign) * Channel operations (create, update, delete) * Organization changes (settings, members) **Location:** Web Dashboard → Organization → Audit Logs *** ### Webhooks [Section titled “Webhooks”](#webhooks) Receive real-time notifications about events in your apps via HTTP webhooks. **Supported events:** * `apps` - App created/updated/deleted * `app_versions` - Bundle uploaded/deleted * `channels` - Channel created/updated/deleted * `org_users` - Member added/removed * `orgs` - Organization updated **Features:** * Custom webhook URLs * Event filtering * Delivery logs * Retry mechanism * Test functionality **Location:** Web Dashboard → Organization → Webhooks *** ### Multi-User Collaboration [Section titled “Multi-User Collaboration”](#multi-user-collaboration) Invite team members to your organization with specific roles and permissions. **Features:** * Email invitations * Role assignment * Member management * Access revocation **Location:** Web Dashboard → Organization → Members *** ### API Key Management [Section titled “API Key Management”](#api-key-management) Create, manage, and revoke API keys with optional expiration dates and hashed storage. **Key capabilities:** * Per-app or per-organization keys * Optional expiration dates * Hashed storage (irreversible) * Key rotation support **Location:** Web Dashboard → API Keys [Learn more about API keys →](/docs/public-api/#authentication) *** ### Password Policies [Section titled “Password Policies”](#password-policies) Organization-level password requirements to enforce security standards. **Configurable policies:** * Minimum length * Require uppercase * Require numbers * Require special characters **Location:** Web Dashboard → Organization → Security *** ## Platform Support [Section titled “Platform Support”](#platform-support) ### Multi-Platform Support [Section titled “Multi-Platform Support”](#multi-platform-support) Support for iOS, Android, and Electron apps with a single SDK. **Supported platforms:** * iOS (Capacitor 5, 6, 7, 8) * Android (Capacitor 5, 6, 7, 8) * Electron (NEW in 2025) *** ### Long-Term Support [Section titled “Long-Term Support”](#long-term-support) Continued support for older Capacitor versions to maintain compatibility with legacy apps. **Currently supported:** * Capacitor 8 (latest) * Capacitor 7 * Capacitor 6 * Capacitor 5 *** ### Custom Storage Backends [Section titled “Custom Storage Backends”](#custom-storage-backends) Use your own storage infrastructure (S3, R2, etc.) instead of Capgo’s default storage. [Learn more about custom storage →](/docs/live-updates/custom-storage/) *** ### China Configuration [Section titled “China Configuration”](#china-configuration) Special configuration for apps distributed in mainland China to comply with local regulations. [Learn more about China configuration →](/docs/live-updates/china-configuration/) *** ## Advanced Features [Section titled “Advanced Features”](#advanced-features) ### Custom Update Behavior [Section titled “Custom Update Behavior”](#custom-update-behavior) Configure when and how updates are checked and applied via the SDK. **Configurable options:** * Check interval (`periodCheckDelay` - minimum 600 seconds) * Direct update timing (`directUpdate` - atInstall, onLaunch, always) * Auto-update enable/disable (`autoUpdate`) * Network requirements (Android only - via WorkManager) [Learn more about update behavior →](/docs/live-updates/update-behavior/) *** ### Update Types [Section titled “Update Types”](#update-types) Different update types for different use cases, from instant updates to user-controlled installations. **Available types:** * Background updates (default) * Immediate updates * User-prompted updates * Conditional updates [Learn more about update types →](/docs/live-updates/update-types/) *** ### Credit System [Section titled “Credit System”](#credit-system) Usage-based billing with credits for bandwidth, storage, and other resources. **Features:** * Credit usage tracking * Usage alerts * Top-up via Stripe * Credit ledger **Location:** Web Dashboard → Organization → Credits *** ## Getting Started [Section titled “Getting Started”](#getting-started) Ready to start using these features? Follow our [Quickstart Guide](/docs/getting-started/quickstart/) to set up your first app with Capgo Live Updates. ## Need Help? [Section titled “Need Help?”](#need-help) * [Join our Discord](https://discord.capgo.app) for community support * [Check the FAQ](/docs/faq/) for common questions * [Browse API documentation](/docs/public-api/) for API integration * [Contact support](https://capgo.app/consulting/) for enterprise assistance # CI/CD Integrations > Integrate Capgo Live Updates with your favorite CI/CD platform for automated deployment workflows. Automate your Capgo Live Updates deployment process by integrating with popular CI/CD platforms. These integrations allow you to automatically deploy app updates whenever you push code changes, test feature branches, and manage multiple deployment environments. ## Available Integrations [Section titled “Available Integrations”](#available-integrations) Choose your CI/CD platform to get started with automated deployments: [Azure DevOps ](/docs/live-updates/integrations/azure-devops/)Integrate with Azure DevOps Pipelines for automated builds, testing, and deployment workflows. [GitLab CI/CD ](/docs/live-updates/integrations/gitlab-ci/)Set up GitLab CI/CD pipelines to automatically deploy your app updates with comprehensive environment management. [GitHub Actions ](/docs/live-updates/integrations/github-actions/)Use GitHub Actions for powerful automation with multi-channel deployments and environment protection. [Bitbucket Pipelines ](/docs/live-updates/integrations/bitbucket-pipeline/)Deploy with Bitbucket Pipelines using simple or advanced configurations for multiple environments. ## What You’ll Get [Section titled “What You’ll Get”](#what-youll-get) All integration guides include: * **Simple Setup**: Basic configuration to get started quickly * **Advanced Workflows**: Multi-environment deployments with staging and production * **Feature Branch Testing**: Automatic deployment of feature branches to test channels * **Security Best Practices**: Secure secret management and environment protection * **Monitoring**: Notifications and logging for deployment status Tip **New to CI/CD?** Start with the simple configuration for your platform, then gradually add more advanced features like multi-channel deployments and automated testing as your needs grow. ## Common Features [Section titled “Common Features”](#common-features) Each integration supports: * **Automated Builds**: Trigger deployments on code changes * **Multi-Channel Support**: Deploy to different channels (development, staging, production) * **Pull Request/Merge Request Testing**: Test changes in isolated environments * **Encryption Support**: Secure deployments with Capgo’s encryption feature * **Environment Protection**: Manual approvals and restricted access for production * **Notifications**: Slack, email, and other notification integrations ## Prerequisites [Section titled “Prerequisites”](#prerequisites) Before setting up any integration, ensure you have: * A Capgo account with an app configured * Your app’s source code in a Git repository * A Capgo API token from [console.capgo.app/apikeys](https://console.capgo.app/apikeys) * Node.js and npm/yarn configured in your project ## Related Documentation [Section titled “Related Documentation”](#related-documentation) * [Channels](/docs/live-updates/channels/) - Learn how to manage different deployment environments * [Encryption](/docs/live-updates/encryption/) - Secure your deployments with end-to-end encryption * [Update Behavior](/docs/live-updates/update-behavior/) - Customize how updates are applied to your apps Choose your CI/CD platform above to start automating your Capgo deployments! # Azure DevOps Integration > Learn how to integrate Capgo Live Updates with Azure DevOps Pipelines for automated deployment of your app updates. Integrate Capgo Live Updates with Azure DevOps Pipelines to automatically deploy your app updates whenever you push code changes. This guide covers setting up automated builds, testing, and deployment workflows. ## Prerequisites [Section titled “Prerequisites”](#prerequisites) Before setting up Azure DevOps integration, ensure you have: * An Azure DevOps organization and project * A Capgo account with an app configured * Your app’s source code in an Azure Repos Git repository * Node.js and npm/yarn configured in your project ## Setting Up Azure DevOps Pipeline [Section titled “Setting Up Azure DevOps Pipeline”](#setting-up-azure-devops-pipeline) ### Step 1: Create Pipeline Variables [Section titled “Step 1: Create Pipeline Variables”](#step-1-create-pipeline-variables) First, set up the necessary variables in your Azure DevOps project: 1. Navigate to your Azure DevOps project 2. Go to **Pipelines** → **Library** → **Variable groups** 3. Create a new variable group named `Capgo-Variables` 4. Add the following variables: | Variable Name | Value | Secure | | ------------- | -------------------- | ------ | | `CAPGO_TOKEN` | Your Capgo API token | ✅ Yes | Tip Get your Capgo API token from [console.capgo.app/apikeys](https://console.capgo.app/apikeys). Your app ID is already configured in your `capacitor.config.ts` file. ## Simple [Section titled “Simple”](#simple) Basic configuration that deploys to production on every push to the main branch: ```yaml # Simple Azure DevOps Pipeline for Capgo Live Updates trigger: branches: include: - main variables: - group: Capgo-Variables jobs: - job: BuildAndDeploy displayName: 'Build and Deploy to Capgo' pool: vmImage: 'ubuntu-latest' steps: - task: NodeTool@0 displayName: 'Setup Node.js' inputs: versionSpec: '22.x' - script: | npm ci npm run test npm run build displayName: 'Install, test and build' - script: | npm install -g @capgo/cli npx @capgo/cli bundle upload --apikey $(CAPGO_TOKEN) --channel production displayName: 'Deploy to Capgo' ``` ## Advanced [Section titled “Advanced”](#advanced) ### Feature Branch Deployments [Section titled “Feature Branch Deployments”](#feature-branch-deployments) Deploy feature branches to test channels for review and testing: ```yaml # Feature branch deployment trigger: branches: include: - feature/* variables: - group: Capgo-Variables jobs: - job: DeployFeature displayName: 'Deploy Feature Branch' pool: vmImage: 'ubuntu-latest' condition: startsWith(variables['Build.SourceBranch'], 'refs/heads/feature/') steps: - task: NodeTool@0 inputs: versionSpec: '22.x' - script: | npm ci npm run test npm run build displayName: 'Install, test and build' - script: | BRANCH_NAME=$(echo "$(Build.SourceBranchName)" | sed 's/[^a-zA-Z0-9-]/-/g') CHANNEL_NAME="feature-$BRANCH_NAME" npm install -g @capgo/cli npx @capgo/cli channel create $CHANNEL_NAME --apikey $(CAPGO_TOKEN) || true npx @capgo/cli bundle upload --apikey $(CAPGO_TOKEN) --channel $CHANNEL_NAME displayName: 'Deploy to Feature Channel' ``` Tip **Testing with Channels**: After deploying to a feature channel, you can test the update in your app by configuring it to use that specific channel. Learn more about [configuring channels in your app](/docs/live-updates/channels/#configuring-the-channel-in-your-app). ### Using Encryption [Section titled “Using Encryption”](#using-encryption) If you’re using [Capgo’s encryption feature](/docs/live-updates/encryption/), you’ll need to store your private key securely in your CI/CD environment. After [setting up encryption keys](/docs/live-updates/encryption/#setting-up-encryption) locally, add your private key to Azure DevOps variables: ```shell # Display your private key content (copy this output) cat .capgo_key_v2 ``` Add this content as `CAPGO_PRIVATE_KEY` in your Azure DevOps variable group (mark as secret), then use it in pipelines: ```yaml # Deploy with encryption - script: | npm install -g @capgo/cli npx @capgo/cli bundle upload --apikey $(CAPGO_TOKEN) --key-data-v2 "$(CAPGO_PRIVATE_KEY)" --channel production displayName: 'Deploy to Capgo with Encryption' ``` Caution **Security Best Practices:** * Never commit the `.capgo_key_v2` file to version control * Store the private key only in secure CI/CD secret management * Use different keys for different environments ### Multi-Channel Configuration [Section titled “Multi-Channel Configuration”](#multi-channel-configuration) For comprehensive information about setting up and managing multiple deployment channels, see the [Channels documentation](/docs/live-updates/channels/). Complete configuration with multiple environments and pull request deployments: ```yaml # Advanced Azure DevOps Pipeline with Multiple Channels trigger: branches: include: - main - develop pr: branches: include: - main - develop variables: - group: Capgo-Variables stages: # Build stage - stage: Build jobs: - job: BuildApp pool: vmImage: 'ubuntu-latest' steps: - task: NodeTool@0 inputs: versionSpec: '22.x' - script: | npm ci npm run test npm run build displayName: 'Install, test and build' - task: PublishBuildArtifacts@1 inputs: pathToPublish: 'dist' artifactName: 'app-build' # Deploy to development - stage: DeployDev condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/develop')) jobs: - deployment: DeployDevelopment environment: development pool: vmImage: 'ubuntu-latest' strategy: runOnce: deploy: steps: - task: NodeTool@0 inputs: versionSpec: '22.x' - task: DownloadBuildArtifacts@0 inputs: artifactName: 'app-build' downloadPath: '$(Pipeline.Workspace)' - script: | npm install -g @capgo/cli npx @capgo/cli bundle upload --apikey $(CAPGO_TOKEN) --channel development --path $(Pipeline.Workspace)/app-build displayName: 'Deploy to Development' # Deploy PR to test channel - stage: DeployPR condition: and(succeeded(), eq(variables['Build.Reason'], 'PullRequest')) jobs: - job: DeployPRChannel pool: vmImage: 'ubuntu-latest' steps: - task: NodeTool@0 inputs: versionSpec: '22.x' - task: DownloadBuildArtifacts@0 inputs: artifactName: 'app-build' downloadPath: '$(Pipeline.Workspace)' - script: | CHANNEL_NAME="pr-$(System.PullRequest.PullRequestNumber)" npm install -g @capgo/cli npx @capgo/cli channel create $CHANNEL_NAME --apikey $(CAPGO_TOKEN) || true npx @capgo/cli bundle upload --apikey $(CAPGO_TOKEN) --channel $CHANNEL_NAME --path $(Pipeline.Workspace)/app-build displayName: 'Deploy to PR Channel' # Deploy to production - stage: DeployProd condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main')) jobs: - deployment: DeployProduction environment: production pool: vmImage: 'ubuntu-latest' strategy: runOnce: deploy: steps: - task: NodeTool@0 inputs: versionSpec: '22.x' - task: DownloadBuildArtifacts@0 inputs: artifactName: 'app-build' downloadPath: '$(Pipeline.Workspace)' - script: | npm install -g @capgo/cli npx @capgo/cli bundle upload --apikey $(CAPGO_TOKEN) --channel production --path $(Pipeline.Workspace)/app-build displayName: 'Deploy to Production' ``` ### Multi-Environment Deployment [Section titled “Multi-Environment Deployment”](#multi-environment-deployment) For complex scenarios with multiple environments: ```yaml # Extended pipeline with multiple environments parameters: - name: deployEnvironment displayName: 'Deploy Environment' type: string default: 'staging' values: - staging - production variables: - group: Capgo-Variables - name: channelName ${{ if eq(parameters.deployEnvironment, 'production') }}: value: 'production' ${{ else }}: value: 'staging' stages: # Build stage - stage: Build jobs: - job: BuildApp pool: vmImage: 'ubuntu-latest' steps: - task: NodeTool@0 inputs: versionSpec: '22.x' - script: | npm ci npm run test npm run build displayName: 'Install, test and build' - task: PublishBuildArtifacts@1 inputs: pathToPublish: 'dist' artifactName: 'app-build' - stage: DeployStaging displayName: 'Deploy to Staging' dependsOn: Build condition: and(succeeded(), eq('${{ parameters.deployEnvironment }}', 'staging')) jobs: - deployment: DeployStaging displayName: 'Deploy to Staging Channel' pool: vmImage: 'ubuntu-latest' environment: 'staging' strategy: runOnce: deploy: steps: - template: deploy-steps.yml parameters: channel: 'staging' - stage: DeployProduction displayName: 'Deploy to Production' dependsOn: Build condition: and(succeeded(), eq('${{ parameters.deployEnvironment }}', 'production')) jobs: - deployment: DeployProduction displayName: 'Deploy to Production Channel' pool: vmImage: 'ubuntu-latest' environment: 'production' strategy: runOnce: deploy: steps: - template: deploy-steps.yml parameters: channel: 'production' ``` ### Deployment Template (deploy-steps.yml) [Section titled “Deployment Template (deploy-steps.yml)”](#deployment-template-deploy-stepsyml) Create a reusable template file `deploy-steps.yml`: deploy-steps.yml ```yaml parameters: - name: channel type: string steps: - task: NodeTool@0 displayName: 'Install Node.js' inputs: versionSpec: '22.x' - task: DownloadBuildArtifacts@0 displayName: 'Download build artifacts' inputs: artifactName: 'app-build' downloadPath: '$(System.ArtifactsDirectory)' - script: | npm install -g @capgo/cli displayName: 'Install Capgo CLI' - script: | npx @capgo/cli bundle upload \ --apikey $(CAPGO_TOKEN) \ --channel ${{ parameters.channel }} \ --path $(System.ArtifactsDirectory)/app-build displayName: 'Upload to Capgo (${{ parameters.channel }})' ``` ### Branch-Based Deployment Strategy [Section titled “Branch-Based Deployment Strategy”](#branch-based-deployment-strategy) Configure different deployment strategies based on Git branches: ```yaml trigger: branches: include: - main - develop - feature/* variables: - group: Capgo-Variables - name: targetChannel ${{ if eq(variables['Build.SourceBranch'], 'refs/heads/main') }}: value: 'production' ${{ elseif eq(variables['Build.SourceBranch'], 'refs/heads/develop') }}: value: 'staging' ${{ else }}: value: 'development' stages: - stage: Build jobs: - job: BuildApp pool: vmImage: 'ubuntu-latest' steps: - task: NodeTool@0 inputs: versionSpec: '22.x' - script: | npm ci npm run test npm run build displayName: 'Install, test and build' - task: PublishBuildArtifacts@1 inputs: pathToPublish: 'dist' artifactName: 'app-build' - stage: Deploy displayName: 'Deploy to $(targetChannel)' dependsOn: Build condition: succeeded() jobs: - deployment: DeployJob displayName: 'Deploy to $(targetChannel) Channel' pool: vmImage: 'ubuntu-latest' environment: '$(targetChannel)' strategy: runOnce: deploy: steps: - template: deploy-steps.yml parameters: channel: '$(targetChannel)' ``` ## Security Best Practices [Section titled “Security Best Practices”](#security-best-practices) ### Secure Variable Management [Section titled “Secure Variable Management”](#secure-variable-management) 1. **Use Variable Groups**: Store sensitive data in Azure DevOps variable groups 2. **Mark as Secret**: Always mark API tokens and keys as secret variables 3. **Scope Access**: Limit variable group access to specific pipelines and users 4. **Rotate Keys**: Regularly rotate your Capgo API tokens ## Monitoring and Notifications [Section titled “Monitoring and Notifications”](#monitoring-and-notifications) ### Teams Integration [Section titled “Teams Integration”](#teams-integration) Add Microsoft Teams notifications to your pipeline: ```yaml - task: ms-teams-deploy-card@1.4.1 displayName: 'Notify Teams on Success' condition: succeeded() inputs: webhookUri: '$(TEAMS_WEBHOOK_URL)' title: 'Capgo Deployment Successful' text: 'App deployed to $(targetChannel) channel' themeColor: '00FF00' - task: ms-teams-deploy-card@1.4.1 displayName: 'Notify Teams on Failure' condition: failed() inputs: webhookUri: '$(TEAMS_WEBHOOK_URL)' title: 'Capgo Deployment Failed' text: 'Deployment to $(targetChannel) failed' themeColor: 'FF0000' ``` ### Email Notifications [Section titled “Email Notifications”](#email-notifications) Configure email notifications for deployment status: ```yaml - task: EmailReport@1 displayName: 'Send Email Report' condition: always() inputs: sendMailConditionConfig: 'Always' subject: 'Capgo Deployment Report - $(Build.BuildNumber)' to: 'team@yourcompany.com' body: | Deployment Status: $(Agent.JobStatus) Channel: $(targetChannel) Build: $(Build.BuildNumber) Commit: $(Build.SourceVersion) ``` ## Troubleshooting [Section titled “Troubleshooting”](#troubleshooting) ### Common Issues [Section titled “Common Issues”](#common-issues) **Pipeline fails with “Capgo CLI not found”:** ```yaml # Ensure global installation - script: | npm install -g @capgo/cli which capgo || echo "Capgo CLI not found in PATH" displayName: 'Install and verify Capgo CLI' ``` **Authentication errors:** ```yaml # Verify token is correctly set - script: | echo "Token length: ${#CAPGO_TOKEN}" if [ -z "$CAPGO_TOKEN" ]; then echo "CAPGO_TOKEN is not set" exit 1 fi displayName: 'Verify Capgo token' env: CAPGO_TOKEN: $(CAPGO_TOKEN) ``` **Build artifacts not found:** ```yaml # List available artifacts for debugging - script: | ls -la $(System.ArtifactsDirectory) find $(System.ArtifactsDirectory) -name "*.js" -o -name "*.html" displayName: 'Debug artifacts' ``` ### Debug Pipeline [Section titled “Debug Pipeline”](#debug-pipeline) Add debugging steps to troubleshoot issues: ```yaml - script: | echo "Build.SourceBranch: $(Build.SourceBranch)" echo "Build.BuildNumber: $(Build.BuildNumber)" echo "Target Channel: $(targetChannel)" displayName: 'Debug Pipeline Variables' - script: | npx @capgo/cli app debug --apikey $(CAPGO_TOKEN) displayName: 'Debug Capgo App Status' ``` ## Next Steps [Section titled “Next Steps”](#next-steps) * Learn about [Channels](/docs/live-updates/channels/) to manage different deployment environments * Explore [Custom Storage](/docs/live-updates/custom-storage/) for advanced deployment scenarios * Set up [Encryption](/docs/live-updates/encryption/) for secure deployments * Configure [Update Behavior](/docs/live-updates/update-behavior/) to customize how updates are applied With Azure DevOps integration, you can automate your Capgo deployments and ensure consistent, reliable updates to your mobile app users. # Bitbucket Pipelines Integration > Learn how to integrate Capgo Live Updates with Bitbucket Pipelines for automated deployment of your app updates. Integrate Capgo Live Updates with Bitbucket Pipelines to automatically deploy your app updates whenever you push code changes. This guide covers setting up automated builds, testing, and deployment workflows. ## Prerequisites [Section titled “Prerequisites”](#prerequisites) Before setting up Bitbucket Pipelines integration, ensure you have: * A Bitbucket account with a repository * A Capgo account with an app configured * Node.js and npm/yarn configured in your project ## Setting Up Bitbucket Pipelines [Section titled “Setting Up Bitbucket Pipelines”](#setting-up-bitbucket-pipelines) ### Step 1: Configure Repository Variables [Section titled “Step 1: Configure Repository Variables”](#step-1-configure-repository-variables) First, set up the necessary variables in your Bitbucket repository: 1. Navigate to your Bitbucket repository 2. Go to **Repository settings** → **Pipelines** → **Repository variables** 3. Add the following variables: | Variable Name | Value | Secured | | ------------- | -------------------- | ------- | | `CAPGO_TOKEN` | Your Capgo API token | ✅ Yes | Tip Get your Capgo API token from [console.capgo.app/apikeys](https://console.capgo.app/apikeys). Your app ID is already configured in your `capacitor.config.ts` file. ## Simple [Section titled “Simple”](#simple) Basic configuration that deploys to production on every push to the main branch: ```yaml # bitbucket-pipelines.yml - Simple Configuration image: node:22 pipelines: branches: main: - step: name: Build and Deploy to Production script: - npm ci - npm run test - npm run build - npm install -g @capgo/cli - npx @capgo/cli bundle upload --apikey $CAPGO_TOKEN --channel production artifacts: - dist/** ``` ## Advanced [Section titled “Advanced”](#advanced) ### Feature Branch Deployments [Section titled “Feature Branch Deployments”](#feature-branch-deployments) Deploy feature branches to test channels for review and testing: ```yaml # Feature branch deployment pipelines: branches: feature/*: - step: name: Deploy Feature Branch script: - npm ci - npm run test - npm run build - BRANCH_NAME=$(echo $BITBUCKET_BRANCH | sed 's/[^a-zA-Z0-9-]/-/g') - CHANNEL_NAME="feature-$BRANCH_NAME" - npm install -g @capgo/cli - npx @capgo/cli channel create $CHANNEL_NAME --apikey $CAPGO_TOKEN || true - npx @capgo/cli bundle upload --apikey $CAPGO_TOKEN --channel $CHANNEL_NAME artifacts: - dist/** ``` Tip **Testing with Channels**: After deploying to a feature channel, you can test the update in your app by configuring it to use that specific channel. Learn more about [configuring channels in your app](/docs/live-updates/channels/#configuring-the-channel-in-your-app). ### Using Encryption [Section titled “Using Encryption”](#using-encryption) If you’re using [Capgo’s encryption feature](/docs/live-updates/encryption/), you’ll need to store your private key securely in your CI/CD environment. After [setting up encryption keys](/docs/live-updates/encryption/#setting-up-encryption) locally, add your private key to Bitbucket variables: ```shell # Display your private key content (copy this output) cat .capgo_key_v2 ``` Add this content as `CAPGO_PRIVATE_KEY` in your Bitbucket repository variables (mark as secured), then use it in pipelines: ```yaml # Deploy with encryption - step: name: Deploy to Capgo with Encryption script: - npm install -g @capgo/cli - npx @capgo/cli bundle upload --apikey $CAPGO_TOKEN --key-data-v2 "$CAPGO_PRIVATE_KEY" --channel production ``` Caution **Security Best Practices:** * Never commit the `.capgo_key_v2` file to version control * Store the private key only in secure CI/CD secret management * Use different keys for different environments ### Multi-Channel Configuration [Section titled “Multi-Channel Configuration”](#multi-channel-configuration) For comprehensive information about setting up and managing multiple deployment channels, see the [Channels documentation](/docs/live-updates/channels/). Complete configuration with multiple environments and pull request deployments: ```yaml # bitbucket-pipelines.yml - Advanced Multi-Channel Configuration image: node:22 definitions: steps: - step: &build-step name: Build Application script: - npm ci - npm run test - npm run build artifacts: - dist/** - step: &deploy-step name: Deploy to Capgo script: - npm install -g @capgo/cli - npx @capgo/cli bundle upload --apikey $CAPGO_TOKEN --channel $CHANNEL_NAME pipelines: branches: main: - step: <<: *build-step - step: <<: *deploy-step name: Deploy to Production deployment: production trigger: manual script: - export CHANNEL_NAME=production - npm install -g @capgo/cli - npx @capgo/cli bundle upload --apikey $CAPGO_TOKEN --channel $CHANNEL_NAME develop: - step: <<: *build-step - step: <<: *deploy-step name: Deploy to Development deployment: development script: - export CHANNEL_NAME=development - npm install -g @capgo/cli - npx @capgo/cli bundle upload --apikey $CAPGO_TOKEN --channel $CHANNEL_NAME pull-requests: '**': - step: <<: *build-step - step: name: Deploy PR to Test Channel script: - CHANNEL_NAME="pr-$BITBUCKET_PR_ID" - npm install -g @capgo/cli - npx @capgo/cli channel create $CHANNEL_NAME --apikey $CAPGO_TOKEN || true - npx @capgo/cli bundle upload --apikey $CAPGO_TOKEN --channel $CHANNEL_NAME artifacts: - dist/** ``` ### Multi-Environment Pipeline [Section titled “Multi-Environment Pipeline”](#multi-environment-pipeline) For complex deployment scenarios with staging and production environments: ```yaml # Multi-environment pipeline image: node:22 pipelines: branches: main: - step: name: Build script: - npm ci - npm run test - npm run build artifacts: - dist/** - step: name: Deploy to Staging deployment: staging script: - npm install -g @capgo/cli - npx @capgo/cli bundle upload --apikey $CAPGO_TOKEN --channel staging - step: name: Deploy to Production deployment: production trigger: manual script: - npm install -g @capgo/cli - npx @capgo/cli bundle upload --apikey $CAPGO_TOKEN --channel production develop: - step: name: Build and Deploy to Development script: - npm ci - npm run test - npm run build - npm install -g @capgo/cli - npx @capgo/cli bundle upload --apikey $CAPGO_TOKEN --channel development artifacts: - dist/** ``` ### Branch-Based Deployment Strategy [Section titled “Branch-Based Deployment Strategy”](#branch-based-deployment-strategy) Automatically deploy different branches to appropriate channels: ```yaml # Dynamic channel deployment image: node:22 definitions: scripts: - script: &determine-channel | if [ "$BITBUCKET_BRANCH" = "main" ]; then export CHANNEL_NAME="production" elif [ "$BITBUCKET_BRANCH" = "develop" ]; then export CHANNEL_NAME="staging" else export CHANNEL_NAME="development" fi echo "Deploying to channel: $CHANNEL_NAME" pipelines: default: - step: name: Build and Deploy script: - npm ci - npm run test - npm run build - *determine-channel - npm install -g @capgo/cli - npx @capgo/cli bundle upload --apikey $CAPGO_TOKEN --channel $CHANNEL_NAME artifacts: - dist/** ``` ### Parallel Pipeline Execution [Section titled “Parallel Pipeline Execution”](#parallel-pipeline-execution) Optimize build times with parallel steps: ```yaml # Parallel execution pipeline image: node:22 pipelines: branches: main: - parallel: - step: name: Run Tests script: - npm ci - npm run test - step: name: Lint Code script: - npm ci - npm run lint - step: name: Build Application script: - npm ci - npm run build artifacts: - dist/** - step: name: Deploy to Production deployment: production script: - npm install -g @capgo/cli - npx @capgo/cli bundle upload --apikey $CAPGO_TOKEN --channel production ``` ## Security Best Practices [Section titled “Security Best Practices”](#security-best-practices) ### Repository Variables [Section titled “Repository Variables”](#repository-variables) 1. **Secured Variables**: Always mark API tokens as secured 2. **Environment Variables**: Use deployment-specific variables when needed 3. **Access Control**: Limit repository access to authorized team members 4. **Token Rotation**: Regularly rotate your Capgo API tokens ### Deployment Environments [Section titled “Deployment Environments”](#deployment-environments) Configure deployment environments for better security: ```yaml # Deployment with environment restrictions pipelines: branches: main: - step: name: Deploy to Production deployment: production trigger: manual script: - npm install -g @capgo/cli - npx @capgo/cli bundle upload --apikey $CAPGO_TOKEN --channel production ``` ## Monitoring and Notifications [Section titled “Monitoring and Notifications”](#monitoring-and-notifications) ### Slack Integration [Section titled “Slack Integration”](#slack-integration) Add Slack notifications to your pipeline: ```yaml # Pipeline with Slack notifications pipelines: branches: main: - step: name: Build and Deploy script: - npm ci - npm run test - npm run build - npm install -g @capgo/cli - npx @capgo/cli bundle upload --apikey $CAPGO_TOKEN --channel production after-script: - | if [ $BITBUCKET_EXIT_CODE -eq 0 ]; then curl -X POST -H 'Content-type: application/json' \ --data '{"text":"✅ Capgo deployment successful for '$BITBUCKET_BRANCH'"}' \ $SLACK_WEBHOOK_URL else curl -X POST -H 'Content-type: application/json' \ --data '{"text":"❌ Capgo deployment failed for '$BITBUCKET_BRANCH'"}' \ $SLACK_WEBHOOK_URL fi ``` ### Email Notifications [Section titled “Email Notifications”](#email-notifications) Configure email notifications through Bitbucket’s built-in features or using external services: ```yaml # Email notification step - step: name: Send Notification script: - | curl -X POST \ -H "Content-Type: application/json" \ -d '{ "to": "team@yourcompany.com", "subject": "Capgo Deployment Status", "body": "Deployment of '$BITBUCKET_BRANCH' completed with status: '$BITBUCKET_EXIT_CODE'" }' \ $EMAIL_SERVICE_URL condition: result: [successful, failed] ``` ## Troubleshooting [Section titled “Troubleshooting”](#troubleshooting) ### Common Issues [Section titled “Common Issues”](#common-issues) **Pipeline fails with “Capgo CLI not found”:** ```yaml # Debug CLI installation - step: name: Debug CLI script: - npm install -g @capgo/cli - which capgo || echo "Capgo CLI not found" - npx @capgo/cli --version ``` **Authentication errors:** ```yaml # Verify token configuration - step: name: Debug Auth script: - | if [ -z "$CAPGO_TOKEN" ]; then echo "CAPGO_TOKEN is not set" exit 1 fi echo "Token length: ${#CAPGO_TOKEN}" ``` **Build artifacts not found:** ```yaml # List build outputs - step: name: Debug Build script: - ls -la dist/ - find dist/ -type f -name "*.js" -o -name "*.html" ``` ### Debug Pipeline [Section titled “Debug Pipeline”](#debug-pipeline) Add debugging information to troubleshoot issues: ```yaml # Debug pipeline pipelines: branches: main: - step: name: Debug Information script: - echo "Branch: $BITBUCKET_BRANCH" - echo "Commit: $BITBUCKET_COMMIT" - echo "Build: $BITBUCKET_BUILD_NUMBER" - env | grep BITBUCKET_ | sort - step: name: Build and Deploy script: - npm ci - npm run test - npm run build - npm install -g @capgo/cli - npx @capgo/cli bundle upload --apikey $CAPGO_TOKEN --channel production ``` ### Pipeline Validation [Section titled “Pipeline Validation”](#pipeline-validation) Enable pipeline validation to catch configuration errors: ```yaml # Enable pipeline validation options: docker: true size: 2x pipelines: branches: main: - step: name: Validate Pipeline script: - echo "Pipeline validation successful" - step: name: Build and Deploy script: # ... deployment steps ``` ## Next Steps [Section titled “Next Steps”](#next-steps) * Learn about [Channels](/docs/live-updates/channels/) to manage different deployment environments * Explore [Custom Storage](/docs/live-updates/custom-storage/) for advanced deployment scenarios * Set up [Encryption](/docs/live-updates/encryption/) for secure deployments * Configure [Update Behavior](/docs/live-updates/update-behavior/) to customize how updates are applied With Bitbucket Pipelines integration, you can automate your Capgo deployments and ensure consistent, reliable updates to your mobile app users. # GitHub Actions Integration > Learn how to integrate Capgo Live Updates with GitHub Actions for automated deployment of your app updates. Integrate Capgo Live Updates with GitHub Actions to automatically deploy your app updates whenever you push code changes. This guide covers setting up automated builds, testing, and deployment workflows using GitHub’s powerful CI/CD platform. ## Prerequisites [Section titled “Prerequisites”](#prerequisites) Before setting up GitHub Actions integration, ensure you have: * A GitHub repository with your app’s source code * A Capgo account with an app configured * Node.js and npm/yarn configured in your project * GitHub Actions enabled for your repository ## Setting Up GitHub Secrets [Section titled “Setting Up GitHub Secrets”](#setting-up-github-secrets) ### Step 1: Configure Repository Secrets [Section titled “Step 1: Configure Repository Secrets”](#step-1-configure-repository-secrets) Set up the necessary secrets in your GitHub repository: 1. Navigate to your GitHub repository 2. Go to **Settings** → **Secrets and variables** → **Actions** 3. Click **New repository secret** and add the following: | Secret Name | Value | | ------------- | -------------------- | | `CAPGO_TOKEN` | Your Capgo API token | Tip Get your Capgo API token from [console.capgo.app/apikeys](https://console.capgo.app/apikeys). Your app ID is already configured in your `capacitor.config.ts` file. ## Simple Production Deployment [Section titled “Simple Production Deployment”](#simple-production-deployment) Start with this basic configuration that deploys to production on every push to the main branch: ```yaml # Simple GitHub Actions Workflow for Capgo Live Updates name: Deploy to Capgo on: push: branches: - main jobs: deploy: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v6 - name: Setup Node.js uses: actions/setup-node@v6 with: node-version: '24' cache: 'npm' - name: Install, test and build run: | npm ci npm run test npm run build - name: Deploy to Capgo run: | npm install -g @capgo/cli npx @capgo/cli bundle upload --channel production env: CAPGO_TOKEN: ${{ secrets.CAPGO_TOKEN }} # For encrypted uploads, add: --key-data-v2 "${{ secrets.CAPGO_PRIVATE_KEY }}" ``` ## Advanced Multi-Channel Configuration [Section titled “Advanced Multi-Channel Configuration”](#advanced-multi-channel-configuration) ### Feature Branch Deployments [Section titled “Feature Branch Deployments”](#feature-branch-deployments) Deploy feature branches to temporary channels for testing: ```yaml # Feature branch deployment name: Deploy Feature Branch to Capgo on: push: branches: - 'feature/**' jobs: deploy-feature: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - uses: actions/setup-node@v6 with: node-version: '24' cache: 'npm' - run: | npm ci npm run test npm run build - name: Deploy to feature channel run: | CHANNEL_NAME=$(echo "${{ github.ref_name }}" | sed 's/[^a-zA-Z0-9]/-/g' | tr '[:upper:]' '[:lower:]') npm install -g @capgo/cli npx @capgo/cli channel create $CHANNEL_NAME --apikey ${{ secrets.CAPGO_TOKEN }} || true npx @capgo/cli bundle upload --apikey ${{ secrets.CAPGO_TOKEN }} --channel $CHANNEL_NAME ``` ### Using Encryption [Section titled “Using Encryption”](#using-encryption) If you’re using [Capgo’s encryption feature](/docs/live-updates/encryption/), you’ll need to store your private key securely in your CI/CD environment. After [setting up encryption keys](/docs/live-updates/encryption/#setting-up-encryption) locally, add your private key to GitHub secrets: ```shell # Display your private key content (copy this output) cat .capgo_key_v2 ``` Add this content as `CAPGO_PRIVATE_KEY` in your GitHub repository secrets, then use it in workflows: ```yaml # Deploy with encryption - name: Deploy to Capgo with Encryption run: | npm install -g @capgo/cli npx @capgo/cli bundle upload --apikey ${{ secrets.CAPGO_TOKEN }} --key-data-v2 "${{ secrets.CAPGO_PRIVATE_KEY }}" --channel production ``` Caution **Security Best Practices:** * Never commit the `.capgo_key_v2` file to version control * Store the private key only in secure CI/CD secret management * Use different keys for different environments ### Multi-Channel Configuration [Section titled “Multi-Channel Configuration”](#multi-channel-configuration) For comprehensive information about setting up and managing multiple deployment channels, see the [Channels documentation](/docs/live-updates/channels/). Complete workflow with development, pull requests, and production deployments: ```yaml # Complete multi-environment workflow name: Deploy to Capgo on: push: branches: [main, develop] pull_request: branches: [main, develop] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - uses: actions/setup-node@v6 with: node-version: '24' cache: 'npm' - run: | npm ci npm run test npm run build - uses: actions/upload-artifact@v6 with: name: dist path: dist/ deploy-development: if: github.ref == 'refs/heads/develop' needs: build runs-on: ubuntu-latest environment: development steps: - uses: actions/setup-node@v6 with: node-version: '24' - uses: actions/download-artifact@v4 with: name: dist path: dist/ - run: | npm install -g @capgo/cli npx @capgo/cli bundle upload --apikey ${{ secrets.CAPGO_TOKEN }} --channel development deploy-pr: if: github.event_name == 'pull_request' needs: build runs-on: ubuntu-latest steps: - uses: actions/setup-node@v6 with: node-version: '24' - uses: actions/download-artifact@v4 with: name: dist path: dist/ - name: Deploy to PR channel run: | CHANNEL_NAME="pr-${{ github.event.number }}" npm install -g @capgo/cli npx @capgo/cli channel create $CHANNEL_NAME --apikey ${{ secrets.CAPGO_TOKEN }} || true npx @capgo/cli bundle upload --apikey ${{ secrets.CAPGO_TOKEN }} --channel $CHANNEL_NAME - name: Comment PR uses: actions/github-script@v7 with: script: | github.rest.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, body: `🚀 This PR has been deployed to Capgo channel: \`pr-${{ github.event.number }}\`\n\nTo test this update in your app, configure it to use this channel. [Learn how to configure channels →](/docs/live-updates/channels/#configuring-the-channel-in-your-app)` }) deploy-production: if: github.ref == 'refs/heads/main' needs: build runs-on: ubuntu-latest environment: production steps: - uses: actions/setup-node@v6 with: node-version: '24' - uses: actions/download-artifact@v4 with: name: dist path: dist/ - run: | npm install -g @capgo/cli npx @capgo/cli bundle upload --apikey ${{ secrets.CAPGO_TOKEN }} --channel production ``` Tip **Testing with Channels**: After deploying to a PR or development channel, you can test the update in your app by configuring it to use that specific channel. Learn more about [configuring channels in your app](/docs/live-updates/channels/#configuring-the-channel-in-your-app). ### Cleanup Feature Channels [Section titled “Cleanup Feature Channels”](#cleanup-feature-channels) Automatically clean up feature channels when branches are deleted: ```yaml name: Cleanup Feature Channels on: delete: jobs: cleanup: runs-on: ubuntu-latest if: github.event.ref_type == 'branch' && startsWith(github.event.ref, 'feature/') steps: - uses: actions/setup-node@v6 with: node-version: '24' - name: Delete Capgo channel run: | CHANNEL_NAME=$(echo "${{ github.event.ref }}" | sed 's/[^a-zA-Z0-9]/-/g' | tr '[:upper:]' '[:lower:]') npm install -g @capgo/cli npx @capgo/cli channel delete $CHANNEL_NAME --apikey ${{ secrets.CAPGO_TOKEN }} || true ``` ## Security and Best Practices [Section titled “Security and Best Practices”](#security-and-best-practices) ### Environment Protection Rules [Section titled “Environment Protection Rules”](#environment-protection-rules) Set up environment protection rules in GitHub: 1. Go to **Settings** → **Environments** in your repository 2. Create environments: `development`, `staging`, `production` 3. For production environment, add: * **Required reviewers**: Add team members who must approve deployments * **Wait timer**: Add a delay before deployment (optional) * **Deployment branches**: Restrict to `main` branch only ### Secure Secrets Management [Section titled “Secure Secrets Management”](#secure-secrets-management) Use environment-specific secrets: ```yaml # Use different secrets per environment deploy-production: environment: production steps: - name: Deploy to Production run: | npx @capgo/cli bundle upload \ --apikey ${{ secrets.CAPGO_PROD_TOKEN }} \ --app ${{ secrets.CAPGO_PROD_APP_ID }} \ --channel production ``` ## Monitoring and Notifications [Section titled “Monitoring and Notifications”](#monitoring-and-notifications) ### Slack Integration [Section titled “Slack Integration”](#slack-integration) Add Slack notifications to your workflow: ```yaml name: Deploy with Notifications jobs: deploy: runs-on: ubuntu-latest steps: # ... deployment steps - name: Notify Slack on Success if: success() uses: 8398a7/action-slack@v3 with: status: success text: '✅ Capgo deployment successful!' fields: repo,message,commit,author,action,eventName,ref,workflow env: SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} - name: Notify Slack on Failure if: failure() uses: 8398a7/action-slack@v3 with: status: failure text: '❌ Capgo deployment failed!' fields: repo,message,commit,author,action,eventName,ref,workflow env: SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} ``` ### Discord Integration [Section titled “Discord Integration”](#discord-integration) Send notifications to Discord: ```yaml - name: Discord notification if: always() uses: Ilshidur/action-discord@master with: args: | Capgo deployment ${{ job.status }}! App: ${{ secrets.CAPGO_APP_ID }} Channel: ${{ github.ref_name }} Commit: ${{ github.sha }} env: DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} ``` ### Email Notifications [Section titled “Email Notifications”](#email-notifications) Configure email notifications: ```yaml - name: Send email notification if: failure() uses: dawidd6/action-send-mail@v3 with: server_address: smtp.gmail.com server_port: 465 username: ${{ secrets.EMAIL_USERNAME }} password: ${{ secrets.EMAIL_PASSWORD }} subject: 'Capgo Deployment Failed - ${{ github.repository }}' to: team@yourcompany.com from: ci-cd@yourcompany.com body: | Deployment failed for ${{ github.repository }} Branch: ${{ github.ref_name }} Commit: ${{ github.sha }} Workflow: ${{ github.workflow }} ``` ## Troubleshooting [Section titled “Troubleshooting”](#troubleshooting) ### Debug Workflow [Section titled “Debug Workflow”](#debug-workflow) Add debugging steps to troubleshoot issues: ```yaml - name: Debug environment run: | echo "Node version: $(node --version)" echo "NPM version: $(npm --version)" echo "Working directory: $(pwd)" echo "Files in dist/: $(ls -la dist/ || echo 'No dist directory')" echo "Environment variables:" env | grep -E "(GITHUB_|CAPGO_)" | sort - name: Test Capgo CLI run: | npx @capgo/cli --version npx @capgo/cli app debug --apikey ${{ secrets.CAPGO_TOKEN }} --app ${{ secrets.CAPGO_APP_ID }} ``` ### Common Issues and Solutions [Section titled “Common Issues and Solutions”](#common-issues-and-solutions) **Workflow fails with “CAPGO\_TOKEN not found”:** ```yaml - name: Verify secrets run: | if [ -z "${{ secrets.CAPGO_TOKEN }}" ]; then echo "ERROR: CAPGO_TOKEN secret is not set" exit 1 fi echo "CAPGO_TOKEN is set (length: ${#CAPGO_TOKEN})" env: CAPGO_TOKEN: ${{ secrets.CAPGO_TOKEN }} ``` **Build artifacts not found:** ```yaml - name: Debug artifacts run: | echo "Checking for build artifacts..." ls -la dist/ || echo "No dist directory found" find . -name "*.js" -o -name "*.html" | head -10 ``` **Network connectivity issues:** ```yaml - name: Test connectivity run: | ping -c 3 api.capgo.io || echo "Ping failed" curl -I https://api.capgo.io/health || echo "Health check failed" ``` ## Reusable Workflows [Section titled “Reusable Workflows”](#reusable-workflows) Create reusable workflows for consistency across projects: .github/workflows/reusable-capgo-deploy.yml ```yaml name: Reusable Capgo Deploy on: workflow_call: inputs: environment: required: true type: string channel: required: true type: string secrets: CAPGO_TOKEN: required: true CAPGO_APP_ID: required: true jobs: deploy: runs-on: ubuntu-latest environment: ${{ inputs.environment }} steps: - uses: actions/checkout@v6 - name: Setup Node.js uses: actions/setup-node@v6 with: node-version: '24' cache: 'npm' - name: Install and build run: | npm ci npm run build - name: Deploy to Capgo run: | npm install -g @capgo/cli npx @capgo/cli bundle upload \ --apikey ${{ secrets.CAPGO_TOKEN }} \ --app ${{ secrets.CAPGO_APP_ID }} \ --channel ${{ inputs.channel }} ``` Use the reusable workflow: .github/workflows/deploy.yml ```yaml name: Deploy App on: push: branches: [main, develop] jobs: deploy-dev: if: github.ref == 'refs/heads/develop' uses: ./.github/workflows/reusable-capgo-deploy.yml with: environment: development channel: development secrets: CAPGO_TOKEN: ${{ secrets.CAPGO_TOKEN }} CAPGO_APP_ID: ${{ secrets.CAPGO_APP_ID }} deploy-prod: if: github.ref == 'refs/heads/main' uses: ./.github/workflows/reusable-capgo-deploy.yml with: environment: production channel: production secrets: CAPGO_TOKEN: ${{ secrets.CAPGO_TOKEN }} CAPGO_APP_ID: ${{ secrets.CAPGO_APP_ID }} ``` ## Next Steps [Section titled “Next Steps”](#next-steps) * Learn about [Channels](/docs/live-updates/channels/) to manage different deployment environments * Explore [Custom Storage](/docs/live-updates/custom-storage/) for advanced deployment scenarios * Set up [Encryption](/docs/live-updates/encryption/) for secure deployments * Configure [Update Behavior](/docs/live-updates/update-behavior/) to customize how updates are applied With GitHub Actions integration, you can leverage GitHub’s powerful CI/CD platform to create sophisticated deployment workflows with built-in security, monitoring, and collaboration features for your Capgo Live Updates. # GitLab CI/CD Integration > Learn how to integrate Capgo Live Updates with GitLab CI/CD for automated deployment of your app updates. Integrate Capgo Live Updates with GitLab CI/CD to automatically deploy your app updates whenever you push code changes. This guide covers setting up automated builds, testing, and deployment workflows. ## Prerequisites [Section titled “Prerequisites”](#prerequisites) Before setting up GitLab CI/CD integration, ensure you have: * A GitLab account with a project repository * A Capgo account with an app configured * Node.js and npm/yarn configured in your project ## Setting Up GitLab CI/CD [Section titled “Setting Up GitLab CI/CD”](#setting-up-gitlab-cicd) ### Step 1: Configure Environment Variables [Section titled “Step 1: Configure Environment Variables”](#step-1-configure-environment-variables) First, set up the necessary variables in your GitLab project: 1. Navigate to your GitLab project 2. Go to **Settings** → **CI/CD** → **Variables** 3. Add the following variables: | Variable Name | Value | Protected | Masked | | ------------- | -------------------- | --------- | ------ | | `CAPGO_TOKEN` | Your Capgo API token | ✅ Yes | ✅ Yes | Tip Get your Capgo API token from [console.capgo.app/apikeys](https://console.capgo.app/apikeys). Your app ID is already configured in your `capacitor.config.ts` file. ## Simple [Section titled “Simple”](#simple) Basic configuration that deploys to production on every push to the main branch: ```yaml # .gitlab-ci.yml - Simple Configuration image: node:22 stages: - build - deploy variables: npm_config_cache: "$CI_PROJECT_DIR/.npm" build: stage: build script: - npm ci - npm run test - npm run build artifacts: paths: - dist/ expire_in: 1 hour only: - main deploy_production: stage: deploy script: - npm install -g @capgo/cli - npx @capgo/cli bundle upload --apikey $CAPGO_TOKEN --channel production # For encrypted uploads, add: --key-data-v2 "$CAPGO_PRIVATE_KEY" dependencies: - build only: - main ``` ## Advanced [Section titled “Advanced”](#advanced) ### Feature Branch Deployments [Section titled “Feature Branch Deployments”](#feature-branch-deployments) Deploy feature branches to test channels for review and testing: ```yaml # Feature branch deployment deploy_feature: stage: deploy script: - npm install -g @capgo/cli - CHANNEL_NAME="feature-$(echo $CI_COMMIT_REF_NAME | sed 's/[^a-zA-Z0-9-]/-/g')" - npx @capgo/cli channel create $CHANNEL_NAME --apikey $CAPGO_TOKEN || true - npx @capgo/cli bundle upload --apikey $CAPGO_TOKEN --channel $CHANNEL_NAME dependencies: - build only: - /^feature\/.*$/ environment: name: feature/$CI_COMMIT_REF_NAME url: https://your-app.com/channels/$CHANNEL_NAME ``` Tip **Testing with Channels**: After deploying to a feature channel, you can test the update in your app by configuring it to use that specific channel. Learn more about [configuring channels in your app](/docs/live-updates/channels/#configuring-the-channel-in-your-app). ### Using Encryption [Section titled “Using Encryption”](#using-encryption) If you’re using [Capgo’s encryption feature](/docs/live-updates/encryption/), you’ll need to store your private key securely in your CI/CD environment. After [setting up encryption keys](/docs/live-updates/encryption/#setting-up-encryption) locally, add your private key to GitLab variables: ```shell # Display your private key content (copy this output) cat .capgo_key_v2 ``` Add this content as `CAPGO_PRIVATE_KEY` in your GitLab project variables (mark as protected and masked), then use it in pipelines: ```yaml # Deploy with encryption deploy_production: script: - npm install -g @capgo/cli - npx @capgo/cli bundle upload --apikey $CAPGO_TOKEN --key-data-v2 "$CAPGO_PRIVATE_KEY" --channel production ``` Caution **Security Best Practices:** * Never commit the `.capgo_key_v2` file to version control * Store the private key only in secure CI/CD secret management * Use different keys for different environments ### Multi-Channel Configuration [Section titled “Multi-Channel Configuration”](#multi-channel-configuration) For comprehensive information about setting up and managing multiple deployment channels, see the [Channels documentation](/docs/live-updates/channels/). Complete configuration with multiple environments and merge request deployments: ```yaml # .gitlab-ci.yml - Advanced Multi-Channel Configuration image: node:22 stages: - build - deploy variables: npm_config_cache: "$CI_PROJECT_DIR/.npm" # Build stage build: stage: build script: - npm ci - npm run test - npm run build artifacts: paths: - dist/ expire_in: 24 hours # Deploy to development channel deploy_development: stage: deploy script: - npm install -g @capgo/cli - npx @capgo/cli bundle upload --apikey $CAPGO_TOKEN --channel development dependencies: - build only: - develop environment: name: development # Deploy merge requests to test channels deploy_mr: stage: deploy script: - npm install -g @capgo/cli - CHANNEL_NAME="mr-$CI_MERGE_REQUEST_IID" - npx @capgo/cli channel create $CHANNEL_NAME --apikey $CAPGO_TOKEN || true - npx @capgo/cli bundle upload --apikey $CAPGO_TOKEN --channel $CHANNEL_NAME dependencies: - build only: - merge_requests environment: name: review/$CI_MERGE_REQUEST_IID url: https://your-app.com/channels/mr-$CI_MERGE_REQUEST_IID on_stop: cleanup_mr # Cleanup MR channels when MR is closed cleanup_mr: stage: deploy script: - npm install -g @capgo/cli - npx @capgo/cli channel delete mr-$CI_MERGE_REQUEST_IID --apikey $CAPGO_TOKEN || true when: manual environment: name: review/$CI_MERGE_REQUEST_IID action: stop only: - merge_requests # Deploy to staging deploy_staging: stage: deploy script: - npm install -g @capgo/cli - npx @capgo/cli bundle upload --apikey $CAPGO_TOKEN --channel staging dependencies: - build only: - develop environment: name: staging # Deploy to production deploy_production: stage: deploy script: - npm install -g @capgo/cli - npx @capgo/cli bundle upload --apikey $CAPGO_TOKEN --channel production dependencies: - build only: - main environment: name: production ``` ### Multi-Environment with Manual Approval [Section titled “Multi-Environment with Manual Approval”](#multi-environment-with-manual-approval) For production deployments requiring manual approval: ```yaml deploy_production: stage: deploy script: - npm install -g @capgo/cli - npx @capgo/cli bundle upload --apikey $CAPGO_TOKEN --channel production dependencies: - build only: - main when: manual environment: name: production ``` ### Branch-Based Deployment Strategy [Section titled “Branch-Based Deployment Strategy”](#branch-based-deployment-strategy) Deploy different branches to appropriate channels automatically: ```yaml # Dynamic channel deployment based on branch deploy: stage: deploy script: - npm install -g @capgo/cli - | if [ "$CI_COMMIT_REF_NAME" = "main" ]; then CHANNEL="production" elif [ "$CI_COMMIT_REF_NAME" = "develop" ]; then CHANNEL="staging" else CHANNEL="development" fi - npx @capgo/cli bundle upload --apikey $CAPGO_TOKEN --channel $CHANNEL dependencies: - build environment: name: $CHANNEL ``` ## Security Best Practices [Section titled “Security Best Practices”](#security-best-practices) ### Protected Variables [Section titled “Protected Variables”](#protected-variables) 1. **Mark Sensitive Variables**: Always mark API tokens as protected and masked 2. **Branch Protection**: Use protected variables for production deployments 3. **Access Control**: Limit variable access to maintainers only 4. **Regular Rotation**: Rotate API tokens regularly ### Secure Pipeline Configuration [Section titled “Secure Pipeline Configuration”](#secure-pipeline-configuration) ```yaml # Use protected variables for production deploy_production: stage: deploy script: - npm install -g @capgo/cli - npx @capgo/cli bundle upload --apikey $CAPGO_TOKEN --channel production only: refs: - main variables: - $CI_COMMIT_REF_PROTECTED == "true" ``` ## Monitoring and Notifications [Section titled “Monitoring and Notifications”](#monitoring-and-notifications) ### Slack Integration [Section titled “Slack Integration”](#slack-integration) Add Slack notifications to your pipeline: ```yaml notify_success: stage: .post image: alpine:latest before_script: - apk add --no-cache curl script: - | curl -X POST -H 'Content-type: application/json' \ --data '{"text":"✅ Capgo deployment successful for '"$CI_COMMIT_REF_NAME"'"}' \ $SLACK_WEBHOOK_URL when: on_success notify_failure: stage: .post image: alpine:latest before_script: - apk add --no-cache curl script: - | curl -X POST -H 'Content-type: application/json' \ --data '{"text":"❌ Capgo deployment failed for '"$CI_COMMIT_REF_NAME"'"}' \ $SLACK_WEBHOOK_URL when: on_failure ``` ### Email Notifications [Section titled “Email Notifications”](#email-notifications) Configure email notifications in your GitLab project settings or use the API: ```yaml notify_email: stage: .post script: - | curl --request POST \ --header "PRIVATE-TOKEN: $GITLAB_API_TOKEN" \ --form "to=team@yourcompany.com" \ --form "subject=Capgo Deployment Status" \ --form "body=Deployment of $CI_COMMIT_REF_NAME completed with status: $CI_JOB_STATUS" \ "https://gitlab.com/api/v4/projects/$CI_PROJECT_ID/emails" when: always ``` ## Troubleshooting [Section titled “Troubleshooting”](#troubleshooting) ### Common Issues [Section titled “Common Issues”](#common-issues) **Pipeline fails with “Capgo CLI not found”:** ```yaml # Debug CLI installation debug_cli: script: - npm install -g @capgo/cli - which capgo || echo "Capgo CLI not found" - npx @capgo/cli --version ``` **Authentication errors:** ```yaml # Verify token configuration debug_auth: script: - | if [ -z "$CAPGO_TOKEN" ]; then echo "CAPGO_TOKEN is not set" exit 1 fi echo "Token length: ${#CAPGO_TOKEN}" ``` **Build artifacts not found:** ```yaml # List build outputs debug_build: script: - ls -la dist/ - find dist/ -type f -name "*.js" -o -name "*.html" ``` ### Debug Pipeline [Section titled “Debug Pipeline”](#debug-pipeline) Add debugging information to troubleshoot issues: ```yaml debug: stage: build script: - echo "Branch: $CI_COMMIT_REF_NAME" - echo "Commit: $CI_COMMIT_SHA" - echo "Build: $CI_PIPELINE_ID" - env | grep CI_ | sort only: - branches ``` ## Next Steps [Section titled “Next Steps”](#next-steps) * Learn about [Channels](/docs/live-updates/channels/) to manage different deployment environments * Explore [Custom Storage](/docs/live-updates/custom-storage/) for advanced deployment scenarios * Set up [Encryption](/docs/live-updates/encryption/) for secure deployments * Configure [Update Behavior](/docs/live-updates/update-behavior/) to customize how updates are applied With GitLab CI/CD integration, you can automate your Capgo deployments and ensure consistent, reliable updates to your mobile app users. # Rollbacks > Learn how to manage rollbacks in Capgo, allowing you to revert to previous app versions seamlessly when needed. While Capgo’s live updates allow you to quickly deliver improvements and fixes to your users, there may be situations where you need to roll back to a previous version of your app. Perhaps a new update introduced an unexpected critical issue, or maybe you want to revert a specific change while you work on a fix. Capgo provides several ways to manage a channel’s builds and control the version of your app that users receive, including both manual rollback options and automatic safety mechanisms. ## Automatic Rollback Protection [Section titled “Automatic Rollback Protection”](#automatic-rollback-protection) Capgo includes a built-in safety mechanism to protect your users from broken updates. If a JavaScript error occurs before the `notifyAppReady()` method is called, the plugin will automatically roll back to the previous working version. ### How Automatic Rollback Works [Section titled “How Automatic Rollback Works”](#how-automatic-rollback-works) When a new update is downloaded and applied, Capgo expects your app to call `notifyAppReady()` within a configurable timeframe to confirm that the update loaded successfully. This method signals that: * The JavaScript bundle loaded without critical errors * Your app’s core functionality is working * The update is safe to keep If `notifyAppReady()` is not called due to a JavaScript crash or critical error, Capgo will: 1. Detect that the update failed to initialize properly 2. Automatically revert to the previous working bundle 3. Mark the problematic update as failed to prevent it from being applied again Tip Make sure to call `notifyAppReady()` in your app’s initialization code after your core components have loaded successfully. This ensures the automatic rollback protection works as intended. ```javascript import { CapacitorUpdater } from '@capgo/capacitor-updater' // Call this after your app has successfully initialized await CapacitorUpdater.notifyAppReady() ``` This automatic protection helps ensure that even if you accidentally push a broken update, your users won’t be stuck with a non-functional app. ### Configuring the Timeout [Section titled “Configuring the Timeout”](#configuring-the-timeout) You can configure how long Capgo waits for `notifyAppReady()` to be called by setting the `appReadyTimeout` in your Capacitor configuration: ```json { "plugins": { "CapacitorUpdater": { "appReadyTimeout": 10000 } } } ``` The `appReadyTimeout` value is specified in milliseconds. The default timeout is typically 10 seconds, but you can adjust this based on your app’s initialization requirements. If your app takes longer to load due to complex initialization processes, you may want to increase this value. ## Rolling Back to a Previous Bundle [Section titled “Rolling Back to a Previous Bundle”](#rolling-back-to-a-previous-bundle) Every time you upload a new build and assign it to a channel, Capgo keeps a history of those builds. If you need to revert a specific update, you can select one of these previous builds to redeploy to the channel. ![Rollback UI interface](/rollback_ui.webp) The primary way to roll back is through the rollback interface, which is located in the 4th tab (History) when viewing a channel in the Capgo Dashboard. This tab provides a comprehensive view of all available builds for the channel, allowing you to easily select and revert to any previous version. To roll back using the History tab: 1. Log in to the [Capgo Dashboard](https://app.capgo.io). 2. Navigate to the “Channels” section. 3. Click the name of the channel you want to roll back. 4. Go to the 4th tab (History) in the channel view. 5. Find the build you want to revert to in the build history. 6. Select that build to make it the active build for the channel. 7. Confirm that you want to roll back to this build. ### Alternative Method: Using the Crown Icon [Section titled “Alternative Method: Using the Crown Icon”](#alternative-method-using-the-crown-icon) As a second way, you can also roll back directly from the first tab by clicking the crown icon next to any build in the channel’s build history: 1. In the first tab of the channel view, find the build you want to revert to. 2. Click the crown icon next to that build to make it the active build for the channel. ![Channel management options](/select_bundle.webp) 3. Confirm that you want to roll back to this build. Note Rolling back to a previous build only affects the selected channel. If you have multiple channels (e.g. Production, Staging, etc.), you’ll need to repeat the rollback process for each affected channel. After rolling back, devices configured to listen to the updated channel will receive the previous build the next time they check for an update. The rolled-back build will be treated as a new update, so the usual update flow and conditions apply. ## Unlinking a Channel [Section titled “Unlinking a Channel”](#unlinking-a-channel) If you want to temporarily halt updates on a channel while you investigate an issue, you can unlink the channel from its current build. To unlink a channel: 1. Navigate to the channel in the Capgo Dashboard. 2. Click the “Unlink” button next to the current build. 3. Confirm that you want to unlink the channel. Once a channel is unlinked, it will not distribute any new updates. Devices configured to that channel will stay on their current build until the channel is linked to a build again. This is useful if you’ve identified a problem with an update but aren’t yet sure which build you want to roll back to. Unlinking the channel gives you time to investigate without pushing out further updates. ## Forcing the Built-In Bundle [Section titled “Forcing the Built-In Bundle”](#forcing-the-built-in-bundle) In more severe situations, you may want to revert all devices on a channel back to the web build that was originally packaged with your app’s native binary. This is known as the “built-in bundle”. To force the built-in bundle on a channel: 1. Navigate to the channel in the Capgo Dashboard. 2. Click the “Built-in Bundle” button. 3. Confirm that you want to force the built-in bundle. When you force the built-in bundle, all devices configured to that channel will revert back to the original packaged web build on their next update check. This happens regardless of what build they’re currently on. This is a more aggressive rollback option than reverting to a specific previous build, as it discards all live updates released since the app was last published to the app stores. Caution Be cautious when forcing the built-in bundle, as it will affect all devices on the channel. Make sure you’ve considered the impact and have a plan to move forward before taking this action. ## Monitoring and Responding to Issues [Section titled “Monitoring and Responding to Issues”](#monitoring-and-responding-to-issues) To catch issues quickly and minimize the impact of problematic updates, it’s important to have a plan for monitoring your releases and responding to problems. Some strategies include: * Monitoring crash reports and user feedback immediately after releasing an update * Using phased rollouts or a staged channel system to test updates on a smaller group before wide release * Having a clear decision process for when to roll back, unlink, or force the built-in bundle, and who has the authority to do so * Communicating to users about the issue and the resolution, if appropriate By combining careful monitoring with the ability to quickly manage problematic updates, you can deliver a continuously improving app experience while minimizing disruptions for your users. # Update Behavior > Explore the comprehensive update behavior of Capgo, designed to deliver seamless updates to your app users without interrupting their experience. When you release an update to your Capgo app, you probably want your users to receive that update as soon as possible. But you also don’t want to disrupt their experience by forcing them to wait for a download or restart the app in the middle of a session. Capgo’s update behavior is designed to strike a balance between delivering updates quickly and minimizing disruption to your users. ## Default Update Flow [Section titled “Default Update Flow”](#default-update-flow) By default, here’s how Capgo handles app updates: 1. On app launch, the Capgo plugin checks to see if a new update is available. 2. If an update is found, it’s downloaded in the background while the user continues using the current version of the app. 3. Once the download completes, Capgo waits for the user to either background the app or kill it entirely. 4. When the user next launches the app, they’ll be running the updated version. This flow ensures that users are always running the latest version of your app, without ever being interrupted by update prompts or forced to wait for downloads. Tip Capgo also checks for updates when the app resumes from the background, so users will receive updates even if they don’t fully quit the app. ## Why This Approach? [Section titled “Why This Approach?”](#why-this-approach) Applying updates on a background or kill event has a few key benefits for user experience: * Users aren’t interrupted by update prompts or forced to wait for downloads in the middle of a session. * Updates are applied seamlessly in between sessions, so the experience of launching the app is always fresh. * You can deliver updates frequently without worrying about disrupting active users. The main downside is that if a user backgrounds and quickly resumes your app, they may lose any unsaved state since the update was applied in between those actions. To mitigate this, we recommend: * Saving state frequently and restoring it gracefully when the app resumes. * Avoiding very frequent updates that modify large parts of the app state. * Considering customizing the update behavior for sensitive flows (see below). ## Customizing When Updates Are Applied [Section titled “Customizing When Updates Are Applied”](#customizing-when-updates-are-applied) In some cases, you may want more control over exactly when an update is applied. For example, you might want to ensure a user completes an in-progress flow before updating, or coordinate an app update with a server-side change. Capgo provides a `setDelay` function that lets you specify conditions that must be met before an update is installed: ```typescript import { CapacitorUpdater } from '@capgo/capacitor-updater'; await CapacitorUpdater.setMultiDelay({ delayConditions: [ { kind: 'date', value: '2023-06-01T00:00:00.000Z', }, { kind: 'background', value: '60000', }, ], }); ``` This example would delay installing an update until after June 1, 2023 AND the app has been backgrounded for at least 60 seconds. The available delay conditions are: * `date`: Wait until after a specific date/time to apply the update. * `background`: Wait a minimum duration after the app is backgrounded to apply the update. * `nativeVersion`: Wait for a native binary with a minimum version to be installed before applying the update. * `kill`: Wait until the next app kill event to apply the update. You can mix and match these conditions to precisely control when an update is installed. Danger Note that the `kill` condition currently triggers the update after the first kill event, not the next background event like the other conditions. This inconsistency will be fixed in a future release. ## Applying Updates Immediately [Section titled “Applying Updates Immediately”](#applying-updates-immediately) For critical updates or apps with very simple state, you may want to apply an update as soon as it’s downloaded, without waiting for a background or kill event. Capgo supports this via the `directUpdate` configuration option. Recommended: Use Delta (Manifest) Updates with Direct Update When using `directUpdate`, we **strongly recommend** enabling [Delta (manifest) Updates](/docs/live-updates/differentials/) to minimize download times and improve the user experience. Delta (manifest) updates only download changed files instead of the entire bundle, which is especially important when updates are applied immediately while users are actively using your app. **Why this matters for Direct Updates:** * **Faster updates**: Smaller downloads mean updates complete quickly, reducing the time users see loading screens * **Better mobile experience**: Users on cellular networks or slower connections won’t face long wait times * **Lower bandwidth usage**: Only changed files are downloaded, saving data for both you and your users When `directUpdate` is enabled in your `capacitor.config`, the CLI detects it. In non-interactive environments it sends Delta (manifest) updates automatically, and in interactive environments it prompts you to confirm before uploading. Use `--no-delta` to force a full bundle upload. To enable Delta (manifest) updates, simply use the `--delta` flag when uploading bundles: ```shell npx @capgo/cli@latest bundle upload --delta ``` Learn more in the [Delta (manifest) Updates documentation](/docs/live-updates/differentials/). `directUpdate` is set in your `capacitor.config.ts` file, not in JavaScript code. It supports three values: * `false` (default): Never do direct updates (use default behavior: download at start, set when backgrounded) * `'atInstall'`: Direct update only when app is installed, updated from store, otherwise act as directUpdate = false * `'onLaunch'`: Direct update only on app installed, updated from store or after app kill, otherwise act as directUpdate = false * `'always'`: Direct update in all previous cases (app installed, updated from store, after app kill or app resume), never act as directUpdate = false * `true` (deprecated): Same as `'always'` for backward compatibility ```typescript import { CapacitorConfig } from '@capacitor/cli'; const config: CapacitorConfig = { plugins: { CapacitorUpdater: { autoUpdate: true, directUpdate: 'always', // or 'atInstall' for updates only on app install/update autoSplashscreen: true, // NEW: Automatically handle splashscreen keepUrlPathAfterReload: true, }, SplashScreen: { launchAutoHide: false, // Still required when using directUpdate }, }, }; export default config; ``` Note **Important**: `directUpdate` only applies updates when the app actually checks for them. By default, this happens only at app startup or when resuming from background. Note that `periodCheckDelay` is not compatible with `directUpdate`. With `directUpdate` enabled, Capgo will immediately apply an update as soon as the download completes during an update check, even if the user is actively using the app. Without periodic checking enabled, this means updates will only be applied when the app starts or resumes from background. Note that because `directUpdate` is a native configuration, it requires some additional handling in your JavaScript code. Caution When using `directUpdate`, you must set `launchAutoHide: false` in the SplashScreen configuration (as shown above) to prevent the splash screen from hiding automatically. This ensures you have full control over when the splash screen is hidden after the update process completes. ## Automatic Splashscreen Handling [Section titled “Automatic Splashscreen Handling”](#automatic-splashscreen-handling) To make `directUpdate` easier to use, Capgo provides an `autoSplashscreen` option that automatically handles hiding the splashscreen for you (available since version 7.6.0): ```typescript const config: CapacitorConfig = { plugins: { CapacitorUpdater: { autoUpdate: true, directUpdate: 'always', // or 'atInstall' autoSplashscreen: true, // Automatically hide splashscreen keepUrlPathAfterReload: true, }, SplashScreen: { launchAutoHide: false, }, }, }; ``` When `autoSplashscreen` is enabled: * The plugin automatically hides the splashscreen when an update is applied * The plugin automatically hides the splashscreen when no update is needed * You don’t need to manually listen for `appReady` events or call `SplashScreen.hide()` ### Manual Splashscreen Handling [Section titled “Manual Splashscreen Handling”](#manual-splashscreen-handling) If you prefer manual control or need custom logic, you can disable `autoSplashscreen` and handle it yourself: ```js import { CapacitorUpdater } from '@capgo/capacitor-updater'; import { SplashScreen } from '@capacitor/splash-screen'; CapacitorUpdater.addListener('appReady', () => { // Hide splash screen SplashScreen.hide(); }); CapacitorUpdater.notifyAppReady(); ``` The `appReady` event fires once the app has finished initializing and applying any pending updates. This is the point at which it’s safe to show your app’s UI, as it ensures the user will see the latest version. In addition to handling the `appReady` event, we recommend setting the `keepUrlPathAfterReload` configuration option to `true` when using `directUpdate`. This preserves the current URL path when the app is reloaded due to an update, helping maintain the user’s location in the app and reducing disorientation. If you don’t handle the `appReady` event and set `keepUrlPathAfterReload` when using `directUpdate`, the user may briefly see a stale version of the app, be taken back to the initial route, or see a flicker as the update is applied. Using `directUpdate` can be useful for delivering critical bug fixes or security patches, but it comes with some tradeoffs: * The user may see a brief flicker or loading state as the update is applied if you don’t properly handle the splashscreen (either with `autoSplashscreen` or manual `appReady` event handling). * If the update modifies the app state or UI, the user may see a disruptive change in the middle of a session. * The user’s location in the app may be lost if `keepUrlPathAfterReload` is not set, potentially disorienting them. * You’ll need to carefully handle saving and restoring state to ensure a smooth transition. If you do enable `directUpdate`, we recommend: * Using `autoSplashscreen: true` for the simplest setup, or manually handling the `appReady` event if you need custom logic. * Setting `keepUrlPathAfterReload` to `true` to preserve the user’s location in the app. * Saving and restoring the app state as needed to avoid losing user progress. * Thoroughly testing your app’s update behavior to ensure there are no jarring transitions, lost state, or disorienting location changes. In most cases, the default update behavior provides the best balance of delivering updates quickly and minimizing disruption. But for apps with specific needs, Capgo provides the flexibility to customize when and how updates are applied. # Update Types > A comprehensive reference of all OTA update types Capgo provides: apply timing, delay conditions, version blocking, and delivery methods. Capgo supports several types of over-the-air (OTA) updates. This page lists and explains all of them so you can choose the right combination for your app. ## Apply Timing [Section titled “Apply Timing”](#apply-timing) Controls **when** an update is applied after it is downloaded. | Type | Description | Use Case | | ----------------------------- | ------------------------------------------------------------------------ | ----------------------------------------------------- | | **Default** | Download in background, apply when user backgrounds or kills the app | Most apps; minimal disruption | | **directUpdate: `atInstall`** | Apply immediately only on fresh install or app store update | New users get latest; existing users use default flow | | **directUpdate: `onLaunch`** | Apply immediately on install, store update, or after app kill | Balance between freshness and session stability | | **directUpdate: `always`** | Apply immediately whenever an update is downloaded (including on resume) | Critical fixes, apps with simple state | Configure in `capacitor.config.ts`: ```typescript plugins: { CapacitorUpdater: { directUpdate: false, // default // or: 'atInstall' | 'onLaunch' | 'always' } } ``` Tip For full details and splashscreen handling, see [Update Behavior](/docs/live-updates/update-behavior/). ## Delay Conditions [Section titled “Delay Conditions”](#delay-conditions) Conditions that must be met **before** an update is installed. Use `setMultiDelay` to combine them (all conditions must be satisfied). | Condition | Description | Example | | ----------------- | ------------------------------------------------------ | ----------------------------------------- | | **date** | Wait until after a specific date/time | Coordinate with server-side release | | **background** | Wait a minimum duration (ms) after app is backgrounded | Avoid applying during quick app switches | | **nativeVersion** | Require a minimum native binary version | Block updates on incompatible native code | | **kill** | Wait until the next app kill event | Apply only on full restart | ```typescript import { CapacitorUpdater } from '@capgo/capacitor-updater'; await CapacitorUpdater.setMultiDelay({ delayConditions: [ { kind: 'date', value: '2023-06-01T00:00:00.000Z' }, { kind: 'background', value: '60000' }, ], }); ``` Danger The `kill` condition triggers after the first kill event, not the next background like the others. This will be fixed in a future release. ## Version Blocking (Channel Policy) [Section titled “Version Blocking (Channel Policy)”](#version-blocking-channel-policy) Controls which **semver updates** a channel will auto-deliver. Set via `--disable-auto-update` on channels. | Strategy | Blocks | Allows | Use Case | | ------------ | ------------------------------------ | -------------------------------------------- | ------------------------------------------------- | | **none** | Nothing | All updates | Default; full auto-update | | **major** | 0.0.0 → 1.0.0 | Same major (e.g. 1.x → 1.y) | Prevent breaking changes from reaching old native | | **minor** | 0.0.0 → 1.1.0, 1.1.0 → 1.2.0 | Same minor (e.g. 1.2.x → 1.2.y) | Stricter control within major | | **patch** | Any change except patch bump | Only 0.0.311 → 0.0.314 | Very strict; patch-only updates | | **metadata** | Updates without `min_update_version` | Updates with explicit compatibility metadata | Custom compatibility rules per bundle | ```bash npx @capgo/cli channel set production --disable-auto-update major ``` Caution `patch` and `metadata` require careful setup. See [CLI commands](/docs/cli/commands/#disable-updates-strategy) and [Version Targeting](/docs/live-updates/version-targeting/) for details. ## Delivery Types [Section titled “Delivery Types”](#delivery-types) How the **bundle is transferred** to the device. | Type | Description | When to Use | | -------------------- | --------------------------------- | ---------------------------------------------------------- | | **Full bundle** | Entire JS bundle is downloaded | First install, large changes, or when delta is unavailable | | **Delta (manifest)** | Only changed files are downloaded | Most updates; faster and bandwidth-friendly | ```bash # Full bundle (default) npx @capgo/cli bundle upload --channel production # Delta updates npx @capgo/cli bundle upload --channel production --delta ``` Tip When using `directUpdate`, enable [Delta updates](/docs/live-updates/differentials/) to minimize download time and improve UX. ## Quick Reference [Section titled “Quick Reference”](#quick-reference) | Category | Types | | -------------------- | --------------------------------------------- | | **Apply timing** | Default, `atInstall`, `onLaunch`, `always` | | **Delay conditions** | `date`, `background`, `nativeVersion`, `kill` | | **Version blocking** | `none`, `major`, `minor`, `patch`, `metadata` | | **Delivery** | Full bundle, Delta (manifest) | ## Related [Section titled “Related”](#related) * [Update Behavior](/docs/live-updates/update-behavior/) — Configure apply timing and delays * [Version Targeting](/docs/live-updates/version-targeting/) — Channel-based version routing * [Delta (manifest) Updates](/docs/live-updates/differentials/) — Enable partial downloads * [Channels](/docs/live-updates/channels/) — Channel configuration and precedence # Version Targeting > Automatically deliver compatible updates to users based on their native app version This guide explains how to automatically deliver the latest compatible bundle to users based on their native app version, **similar to Ionic AppFlow’s approach**. This ensures simplified update management and faster rollouts while preventing compatibility issues. Migrating from Ionic AppFlow? If you’re coming from Ionic AppFlow, this guide is especially important for you. AppFlow automatically matched updates to native versions, and Capgo provides the same capability with even more control and flexibility. See the [AppFlow Migration Guide](/docs/upgrade/from-appflow-to-capgo) for step-by-step migration instructions. ## Overview [Section titled “Overview”](#overview) Capgo’s version targeting system allows you to: * **Automatically deliver compatible updates** to users based on their native app version * **Prevent breaking changes** from reaching incompatible app versions * **Manage multiple app versions** simultaneously without complex logic * **Seamlessly roll out updates** to specific user segments ### Why Version Targeting Matters (Especially for AppFlow Users) [Section titled “Why Version Targeting Matters (Especially for AppFlow Users)”](#why-version-targeting-matters-especially-for-appflow-users) If you’re familiar with **Ionic AppFlow**, you know how critical it is to ensure users receive only compatible updates. AppFlow automatically matched live update bundles to native app versions, preventing incompatible JavaScript from being delivered to older native code. **Capgo provides the same safety guarantees**, with additional features: * More granular control over version matching * Multiple strategies (channels, semver, native constraints) * Better visibility into version distribution * API and CLI control alongside dashboard management This approach is particularly useful when: * You have users on different major versions of your app (e.g., v1.x, v2.x, v3.x) * You need to maintain backward compatibility while rolling out breaking changes * You want to prevent newer bundles from breaking older native code * You’re migrating users gradually from one version to another * **You’re migrating from AppFlow** and want to maintain the same update safety ## How It Works [Section titled “How It Works”](#how-it-works) Capgo uses a multi-layered approach to match users with compatible updates: 1. **Native Version Constraints**: Prevent bundles from being delivered to incompatible native versions 2. **Channel-Based Routing**: Route different app versions to different update channels 3. **Semantic Versioning Controls**: Automatically block updates across major/minor/patch boundaries 4. **Device-Level Overrides**: Target specific devices or user groups ### Version Matching Flow [Section titled “Version Matching Flow”](#version-matching-flow) ```mermaid graph TD A[User Opens App] --> B{Check Device Override} B -->|Override Set| C[Use Override Channel] B -->|No Override| D{Check defaultChannel in App} D -->|Has defaultChannel| E[Use App's defaultChannel] D -->|No defaultChannel| F[Use Cloud Default Channel] C --> G{Check Version Constraints} E --> G F --> G G -->|Compatible| H[Deliver Update] G -->|Incompatible| I[Skip Update] ``` ## Strategy 1: Channel-Based Version Routing [Section titled “Strategy 1: Channel-Based Version Routing”](#strategy-1-channel-based-version-routing) This is the **recommended approach** for managing breaking changes and major version updates. It’s similar to AppFlow’s delivery model. ### Example Scenario [Section titled “Example Scenario”](#example-scenario) * **App v1.x** (100,000 users) → `production` channel * **App v2.x** (50,000 users with breaking changes) → `v2` channel * **App v3.x** (10,000 beta users) → `v3` channel ### Implementation [Section titled “Implementation”](#implementation) #### Step 1: Configure Channels for Each Major Version [Section titled “Step 1: Configure Channels for Each Major Version”](#step-1-configure-channels-for-each-major-version) ```typescript // capacitor.config.ts for version 1.x builds import { CapacitorConfig } from '@capacitor/cli'; const config: CapacitorConfig = { appId: 'com.example.app', appName: 'Example App', plugins: { CapacitorUpdater: { autoUpdate: true, defaultChannel: 'production', // or omit for default } } }; export default config; ``` ```typescript // capacitor.config.ts for version 2.x builds const config: CapacitorConfig = { appId: 'com.example.app', appName: 'Example App', plugins: { CapacitorUpdater: { autoUpdate: true, defaultChannel: 'v2', // Routes v2 users automatically } } }; ``` ```typescript // capacitor.config.ts for version 3.x builds const config: CapacitorConfig = { appId: 'com.example.app', appName: 'Example App', plugins: { CapacitorUpdater: { autoUpdate: true, defaultChannel: 'v3', // Routes v3 users automatically } } }; ``` #### Step 2: Create Channels [Section titled “Step 2: Create Channels”](#step-2-create-channels) ```bash # Create channels for each major version npx @capgo/cli channel create production npx @capgo/cli channel create v2 npx @capgo/cli channel create v3 # Enable self-assignment so apps can switch channels npx @capgo/cli channel set production --self-assign npx @capgo/cli channel set v2 --self-assign npx @capgo/cli channel set v3 --self-assign ``` #### Step 3: Upload Version-Specific Bundles [Section titled “Step 3: Upload Version-Specific Bundles”](#step-3-upload-version-specific-bundles) ```bash # For v1.x users (from v1-maintenance branch) git checkout v1-maintenance npm run build npx @capgo/cli bundle upload --channel production # For v2.x users (from v2-maintenance or main branch) git checkout main npm run build npx @capgo/cli bundle upload --channel v2 # For v3.x users (from beta/v3 branch) git checkout beta npm run build npx @capgo/cli bundle upload --channel v3 ``` Automatic Routing When users open the app, they automatically connect to their designated channel based on the `defaultChannel` in their installed app bundle. No JavaScript code changes required! ### Benefits [Section titled “Benefits”](#benefits) * **Zero code changes** - Channel routing happens automatically * **Clear separation** - Each version has its own update pipeline * **Flexible targeting** - Push updates to specific version groups * **Safe rollouts** - Breaking changes never reach incompatible versions ## Strategy 2: Semantic Versioning Controls [Section titled “Strategy 2: Semantic Versioning Controls”](#strategy-2-semantic-versioning-controls) Use Capgo’s built-in semantic versioning controls to prevent updates across version boundaries. ### Disable Auto-Update Across Major Versions [Section titled “Disable Auto-Update Across Major Versions”](#disable-auto-update-across-major-versions) ```bash # Create a channel that blocks major version updates npx @capgo/cli channel create stable --disable-auto-update major ``` This configuration means: * Users on app version **1.2.3** will receive updates up to **1.9.9** * Users will **NOT** receive version **2.0.0** automatically * Prevents breaking changes from reaching older native code ### Granular Control Options [Section titled “Granular Control Options”](#granular-control-options) ```bash # Block minor version updates (1.2.x won't get 1.3.0) npx @capgo/cli channel set stable --disable-auto-update minor # Block patch updates (1.2.3 won't get 1.2.4) npx @capgo/cli channel set stable --disable-auto-update patch # Allow all updates npx @capgo/cli channel set stable --disable-auto-update none ``` Semantic Versioning Required This strategy only works if you follow semantic versioning (semver) for your app versions. Ensure your version numbers follow the `MAJOR.MINOR.PATCH` format. ## Strategy 3: Native Version Constraints [Section titled “Strategy 3: Native Version Constraints”](#strategy-3-native-version-constraints) Specify minimum native version requirements for bundles to prevent delivery to incompatible devices. ### Using nativeVersion Delay Condition [Section titled “Using nativeVersion Delay Condition”](#using-nativeversion-delay-condition) When uploading a bundle, you can specify a minimum native version: ```bash # This bundle requires native version 2.0.0 or higher npx @capgo/cli bundle upload \ --channel production \ --native-version "2.0.0" ``` How It Works Devices on native version 1.x will NOT receive this bundle. Only devices on 2.0.0+ will get it. This is perfect for updates that require new native APIs or plugins. ### Use Cases [Section titled “Use Cases”](#use-cases) 1. **New Native Plugin Required** ```bash # Bundle needs Camera plugin added in v2.0.0 npx @capgo/cli bundle upload --native-version "2.0.0" ``` 2. **Breaking Native API Changes** ```bash # Bundle uses new Capacitor 6 APIs npx @capgo/cli bundle upload --native-version "3.0.0" ``` 3. **Gradual Migration** ```bash # Test bundle only on latest native version npx @capgo/cli bundle upload \ --channel beta \ --native-version "2.5.0" ``` ## Strategy 4: Auto-Downgrade Prevention [Section titled “Strategy 4: Auto-Downgrade Prevention”](#strategy-4-auto-downgrade-prevention) Prevent users from receiving bundles older than their current native version. ### Enable in Channel Settings [Section titled “Enable in Channel Settings”](#enable-in-channel-settings) In the Capgo dashboard: 1. Go to **Channels** → Select your channel 2. Enable **“Disable auto downgrade under native”** 3. Save changes Or via CLI: ```bash npx @capgo/cli channel set production --disable-downgrade ``` ### Example [Section titled “Example”](#example) * User’s device: Native version **1.2.5** * Channel bundle: Version **1.2.3** * **Result**: Update is blocked (would be a downgrade) This is useful when: * Users manually installed a newer version from the app store * You need to ensure users always have the latest security patches * You want to prevent regression bugs ## Strategy 5: Device-Level Targeting [Section titled “Strategy 5: Device-Level Targeting”](#strategy-5-device-level-targeting) Override channel assignment for specific devices or user groups. ### Force Specific Version for Testing [Section titled “Force Specific Version for Testing”](#force-specific-version-for-testing) ```typescript import { CapacitorUpdater } from '@capgo/capacitor-updater' // Force beta testers to use v3 channel async function assignBetaTesters() { const deviceId = await CapacitorUpdater.getDeviceId() // Check if user is beta tester if (isBetaTester(userId)) { await CapacitorUpdater.setChannel({ channel: 'v3' }) } } ``` ### Dashboard Device Override [Section titled “Dashboard Device Override”](#dashboard-device-override) In the Capgo dashboard: 1. Go to **Devices** → Find device 2. Click **Set Channel** or **Set Version** 3. Override with specific channel or bundle version 4. Device will receive updates from overridden source Testing Updates Use device overrides to test updates on your own device before rolling out to all users. ## Complete AppFlow-Style Workflow [Section titled “Complete AppFlow-Style Workflow”](#complete-appflow-style-workflow) Here’s a complete example combining all strategies: ### 1. Initial Setup (App v1.0.0) [Section titled “1. Initial Setup (App v1.0.0)”](#1-initial-setup-app-v100) ```bash # Create production channel with semver controls npx @capgo/cli channel create production \ --disable-auto-update major \ --disable-downgrade ``` capacitor.config.ts ```typescript const config: CapacitorConfig = { plugins: { CapacitorUpdater: { autoUpdate: true, defaultChannel: 'production', } } }; ``` ### 2. Release Breaking Change (App v2.0.0) [Section titled “2. Release Breaking Change (App v2.0.0)”](#2-release-breaking-change-app-v200) ```bash # Create v2 channel for new version npx @capgo/cli channel create v2 \ --disable-auto-update major \ --disable-downgrade \ --self-assign # Create git branch for v1 maintenance git checkout -b v1-maintenance git push origin v1-maintenance ``` ```typescript // capacitor.config.ts for v2.0.0 const config: CapacitorConfig = { plugins: { CapacitorUpdater: { autoUpdate: true, defaultChannel: 'v2', // New users get v2 channel } } }; ``` ### 3. Push Updates to Both Versions [Section titled “3. Push Updates to Both Versions”](#3-push-updates-to-both-versions) ```bash # Update v1.x users (bug fix) git checkout v1-maintenance # Make changes npx @capgo/cli bundle upload \ --channel production \ --native-version "1.0.0" # Update v2.x users (new feature) git checkout main # Make changes npx @capgo/cli bundle upload \ --channel v2 \ --native-version "2.0.0" ``` ### 4. Monitor Version Distribution [Section titled “4. Monitor Version Distribution”](#4-monitor-version-distribution) Use the Capgo dashboard to track: * How many users are on v1 vs v2 * Bundle adoption rates per version * Errors or crashes per version ### 5. Deprecate Old Version [Section titled “5. Deprecate Old Version”](#5-deprecate-old-version) Once v1 usage drops below threshold: ```bash # Stop uploading to production channel # Optional: Delete v1 maintenance branch git branch -d v1-maintenance # Move all remaining users to default # (They'll need to update via app store) ``` ## Channel Precedence [Section titled “Channel Precedence”](#channel-precedence) When multiple channel configurations exist, Capgo uses this precedence order: 1. **Device Override** (Dashboard or API) - Highest priority 2. **Cloud Override** via `setChannel()` call 3. **defaultChannel** in capacitor.config.ts 4. **Default Channel** (Cloud setting) - Lowest priority Precedence Example If a user’s app has `defaultChannel: 'v2'` but you override their device to `'beta'` in the dashboard, they’ll receive updates from the `'beta'` channel. ## Best Practices [Section titled “Best Practices”](#best-practices) ### 1. Always Set defaultChannel for Major Versions [Section titled “1. Always Set defaultChannel for Major Versions”](#1-always-set-defaultchannel-for-major-versions) ```typescript // ✅ Good: Each major version has explicit channel // v1.x → production // v2.x → v2 // v3.x → v3 // ❌ Bad: Relying on dynamic channel switching // All versions → production, switch manually ``` ### 2. Use Semantic Versioning [Section titled “2. Use Semantic Versioning”](#2-use-semantic-versioning) ```bash # ✅ Good 1.0.0 → 1.0.1 → 1.1.0 → 2.0.0 # ❌ Bad 1.0 → 1.1 → 2 → 2.5 ``` ### 3. Maintain Separate Branches [Section titled “3. Maintain Separate Branches”](#3-maintain-separate-branches) ```bash # ✅ Good: Separate branches per major version main (v3.x) v2-maintenance (v2.x) v1-maintenance (v1.x) # ❌ Bad: Single branch for all versions ``` ### 4. Test Before Rollout [Section titled “4. Test Before Rollout”](#4-test-before-rollout) ```bash # Test on beta channel first npx @capgo/cli bundle upload --channel beta # Monitor for issues, then promote to production npx @capgo/cli bundle upload --channel production ``` ### 5. Monitor Version Distribution [Section titled “5. Monitor Version Distribution”](#5-monitor-version-distribution) Regularly check your dashboard: * Are users upgrading to newer native versions? * Are old versions still getting high traffic? * Should you deprecate old channels? ## Comparison with Ionic AppFlow [Section titled “Comparison with Ionic AppFlow”](#comparison-with-ionic-appflow) For teams migrating from **Ionic AppFlow**, here’s how Capgo’s version targeting compares: | Feature | Ionic AppFlow | Capgo | | ------------------------------ | ----------------------------------------- | --------------------------------------------------------- | | **Version-based routing** | Automatic based on native version | Automatic via `defaultChannel` + multiple strategies | | **Semantic versioning** | Basic support | Advanced with `--disable-auto-update` (major/minor/patch) | | **Native version constraints** | Manual configuration in AppFlow dashboard | Built-in `--native-version` flag in CLI | | **Channel management** | Web UI + CLI | Web UI + CLI + API | | **Device overrides** | Limited device-level control | Full control via Dashboard/API | | **Auto-downgrade prevention** | Yes | Yes via `--disable-downgrade` | | **Multi-version maintenance** | Manual branch/channel management | Automated with channel precedence | | **Self-hosting** | No | Yes (full control) | | **Version analytics** | Basic | Detailed per-version metrics | AppFlow Parity and Beyond Capgo provides **all the version targeting capabilities** that AppFlow offered, plus additional control mechanisms. If you relied on AppFlow’s automatic version matching, you’ll find Capgo equally safe with more flexibility. ## Troubleshooting [Section titled “Troubleshooting”](#troubleshooting) ### Users Not Receiving Updates [Section titled “Users Not Receiving Updates”](#users-not-receiving-updates) Check the following: 1. **Channel Assignment**: Verify device is on correct channel ```typescript const channel = await CapacitorUpdater.getChannel() console.log('Current channel:', channel) ``` 2. **Version Constraints**: Check if bundle has native version requirements * Dashboard → Bundles → Check “Native Version” column 3. **Semver Settings**: Verify channel’s `disable-auto-update` setting ```bash npx @capgo/cli channel list ``` 4. **Device Override**: Check if device has manual override * Dashboard → Devices → Search for device → Check channel/version ### Bundle Delivered to Wrong Version [Section titled “Bundle Delivered to Wrong Version”](#bundle-delivered-to-wrong-version) 1. **Review defaultChannel**: Ensure correct channel in `capacitor.config.ts` 2. **Check Bundle Upload**: Verify bundle was uploaded to intended channel 3. **Inspect Native Version**: Confirm `--native-version` flag was used correctly ### Breaking Changes Affecting Old Versions [Section titled “Breaking Changes Affecting Old Versions”](#breaking-changes-affecting-old-versions) 1. **Immediate Fix**: Override affected devices to safe bundle * Dashboard → Devices → Bulk select → Set Version 2. **Long-term Fix**: Create versioned channels and maintain separate branches 3. **Prevention**: Always test updates on representative devices before rollout ## Migration from Ionic AppFlow [Section titled “Migration from Ionic AppFlow”](#migration-from-ionic-appflow) If you’re migrating from **Ionic AppFlow**, version targeting works very similarly in Capgo, with improved flexibility: ### Concept Mapping [Section titled “Concept Mapping”](#concept-mapping) | AppFlow Concept | Capgo Equivalent | Notes | | ------------------------------ | ----------------------------------------------- | --------------------------------- | | **Deploy Channel** | Capgo Channel | Same concept, more powerful | | **Native Version Lock** | `--native-version` flag | More granular control | | **Channel Priority** | Channel precedence (override → cloud → default) | More transparent precedence | | **Deployment Target** | Channel + semver controls | Multiple strategies available | | **Production Channel** | `production` channel (or any name) | Flexible naming | | **Git-based deployment** | CLI bundle upload from branch | Same workflow | | **Automatic version matching** | `defaultChannel` + version constraints | Enhanced with multiple strategies | ### Key Differences for AppFlow Users [Section titled “Key Differences for AppFlow Users”](#key-differences-for-appflow-users) 1. **More Control**: Capgo gives you multiple strategies (channels, semver, native version) that can be combined 2. **Better Visibility**: Dashboard shows version distribution and compatibility issues 3. **API Access**: Full programmatic control over version targeting 4. **Self-Hosting**: Option to run your own update server with same version logic ### Migration Steps [Section titled “Migration Steps”](#migration-steps) 1. **Map your AppFlow channels** to Capgo channels (usually 1:1) 2. **Set `defaultChannel`** in `capacitor.config.ts` for each major version 3. **Configure semver rules** if you want automatic blocking at version boundaries 4. **Upload version-specific bundles** using `--native-version` flag 5. **Monitor version distribution** in Capgo dashboard Complete Migration Guide For complete migration instructions including SDK replacement and API mapping, see the [AppFlow to Capgo Migration Guide](/docs/upgrade/from-appflow-to-capgo). ## Advanced Patterns [Section titled “Advanced Patterns”](#advanced-patterns) ### Gradual Rollout by Version [Section titled “Gradual Rollout by Version”](#gradual-rollout-by-version) ```typescript // Gradually migrate v1 users to v2 async function migrateUsers() { const deviceId = await CapacitorUpdater.getDeviceId() const rolloutPercentage = 10 // Start with 10% // Hash device ID to get deterministic percentage const hash = hashCode(deviceId) % 100 if (hash < rolloutPercentage) { // User is in rollout group - migrate to v2 await CapacitorUpdater.setChannel({ channel: 'v2' }) } } ``` ### Feature Flags by Version [Section titled “Feature Flags by Version”](#feature-flags-by-version) ```typescript // Enable features based on native version async function checkFeatureAvailability() { const info = await CapacitorUpdater.getDeviceId() const nativeVersion = info.nativeVersion if (compareVersions(nativeVersion, '2.0.0') >= 0) { // Enable features requiring v2.0.0+ enableNewCameraFeature() } } ``` ### A/B Testing Across Versions [Section titled “A/B Testing Across Versions”](#ab-testing-across-versions) ```typescript // Run A/B tests within same native version async function assignABTest() { const nativeVersion = await getNativeVersion() if (nativeVersion.startsWith('2.')) { // Only A/B test on v2 users const variant = Math.random() < 0.5 ? 'v2-test-a' : 'v2-test-b' await CapacitorUpdater.setChannel({ channel: variant }) } } ``` ## Summary [Section titled “Summary”](#summary) Capgo provides multiple strategies for version-specific update delivery: 1. **Channel-Based Routing**: Automatic version separation via `defaultChannel` 2. **Semantic Versioning**: Prevent updates across major/minor/patch boundaries 3. **Native Version Constraints**: Require minimum native version for bundles 4. **Auto-Downgrade Prevention**: Never deliver older bundles to newer native versions 5. **Device Overrides**: Manual control for testing and targeting By combining these strategies, you can achieve AppFlow-style automatic update delivery with even more flexibility and control. Choose the approach that best fits your app’s versioning and deployment workflow. For more details on specific features: * [Breaking Changes Guide](/docs/live-updates/breaking-changes) - Detailed channel versioning strategy * [Channel Management](/docs/live-updates/channels) - Complete channel configuration reference * [Update Behavior](/docs/live-updates/update-behavior) - Native version delays and conditions # Functions and settings > All available method and settings of the plugin # Updater Plugin Config [Section titled “Updater Plugin Config”](#updater-plugin-config) CapacitorUpdater can be configured with these options: | Prop | Type | Description | Default | Since | | ------------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------ | ------------ | | **`appReadyTimeout`** | `number` | Configure the number of milliseconds the native plugin should wait before considering an update ‘failed’. Only available for Android and iOS. | `10000 // (10 seconds)` | | | **`responseTimeout`** | `number` | Configure the number of seconds the native plugin should wait before considering API timeout. Only available for Android and iOS. | `20 // (20 second)` | | | **`autoDeleteFailed`** | `boolean` | Configure whether the plugin should use automatically delete failed bundles. Only available for Android and iOS. | `true` | | | **`autoDeletePrevious`** | `boolean` | Configure whether the plugin should use automatically delete previous bundles after a successful update. Only available for Android and iOS. | `true` | | | **`autoUpdate`** | `boolean` | Configure whether the plugin should use Auto Update via an update server. Only available for Android and iOS. | `true` | | | **`resetWhenUpdate`** | `boolean` | Automatically delete previous downloaded bundles when a newer native app bundle is installed to the device. Setting this to false can broke the auto update flow if the user download from the store a native app bundle that is older than the current downloaded bundle. Upload will be prevented by channel setting downgrade\_under\_native. Only available for Android and iOS. | `true` | | | **`updateUrl`** | `string` | Configure the URL / endpoint to which update checks are sent. Only available for Android and iOS. | `https://plugin.capgo.app/updates` | | | **`channelUrl`** | `string` | Configure the URL / endpoint for channel operations. Only available for Android and iOS. | `https://plugin.capgo.app/channel_self` | | | **`statsUrl`** | `string` | Configure the URL / endpoint to which update statistics are sent. Only available for Android and iOS. Set to "" to disable stats reporting. | `https://plugin.capgo.app/stats` | | | **`publicKey`** | `string` | Configure the public key for end to end live update encryption Version 2 Only available for Android and iOS. | `undefined` | 6.2.0 | | **`version`** | `string` | Configure the current version of the app. This will be used for the first update request. If not set, the plugin will get the version from the native code. Only available for Android and iOS. | `undefined` | 4.17.48 | | **`directUpdate`** | \`boolean | ’always' | 'atInstall' | 'onLaunch’\` | | **`autoSplashscreen`** | `boolean` | Automatically handle splashscreen hiding when using directUpdate. When enabled, the plugin will automatically hide the splashscreen after updates are applied or when no update is needed. This removes the need to manually listen for appReady events and call SplashScreen.hide(). Only works when directUpdate is set to “atInstall”, “always”, “onLaunch”, or true. Requires the @capacitor/splash-screen plugin to be installed and configured with launchAutoHide: false. Requires autoUpdate and directUpdate to be enabled. Only available for Android and iOS. | `false` | 7.6.0 | | **`autoSplashscreenLoader`** | `boolean` | Display a native loading indicator on top of the splashscreen while automatic direct updates are running. Only takes effect when {@link autoSplashscreen} is enabled. Requires the @capacitor/splash-screen plugin to be installed and configured with launchAutoHide: false. Only available for Android and iOS. | `false` | 7.19.0 | | **`autoSplashscreenTimeout`** | `number` | Automatically hide the splashscreen after the specified number of milliseconds when using automatic direct updates. If the timeout elapses, the update continues to download in the background while the splashscreen is dismissed. Set to `0` (zero) to disable the timeout. When the timeout fires, the direct update flow is skipped and the downloaded bundle is installed on the next background/launch. Requires {@link autoSplashscreen} to be enabled. Only available for Android and iOS. | `10000 // (10 seconds)` | 7.19.0 | | **`periodCheckDelay`** | `number` | Configure the delay period for period update check. the unit is in seconds. Only available for Android and iOS. Cannot be less than 600 seconds (10 minutes). | `0 (disabled)` | | | **`localS3`** | `boolean` | Configure the CLI to use a local server for testing or self-hosted update server. | `undefined` | 4.17.48 | | **`localHost`** | `string` | Configure the CLI to use a local server for testing or self-hosted update server. | `undefined` | 4.17.48 | | **`localWebHost`** | `string` | Configure the CLI to use a local server for testing or self-hosted update server. | `undefined` | 4.17.48 | | **`localSupa`** | `string` | Configure the CLI to use a local server for testing or self-hosted update server. | `undefined` | 4.17.48 | | **`localSupaAnon`** | `string` | Configure the CLI to use a local server for testing. | `undefined` | 4.17.48 | | **`localApi`** | `string` | Configure the CLI to use a local api for testing. | `undefined` | 6.3.3 | | **`localApiFiles`** | `string` | Configure the CLI to use a local file api for testing. | `undefined` | 6.3.3 | | **`allowModifyUrl`** | `boolean` | Allow the plugin to modify the updateUrl, statsUrl and channelUrl dynamically from the JavaScript side. | `false` | 5.4.0 | | **`allowModifyAppId`** | `boolean` | Allow the plugin to modify the appId dynamically from the JavaScript side. | `false` | 7.14.0 | | **`allowManualBundleError`** | `boolean` | Allow marking bundles as errored from JavaScript while using manual update flows. When enabled, {@link CapacitorUpdaterPlugin.setBundleError} can change a bundle status to `error`. | `false` | 7.20.0 | | **`persistCustomId`** | `boolean` | Persist the customId set through {@link CapacitorUpdaterPlugin.setCustomId} across app restarts. Only available for Android and iOS. | `false (will be true by default in a future major release v8.x.x)` | 7.17.3 | | **`persistModifyUrl`** | `boolean` | Persist the updateUrl, statsUrl and channelUrl set through {@link CapacitorUpdaterPlugin.setUpdateUrl}, {@link CapacitorUpdaterPlugin.setStatsUrl} and {@link CapacitorUpdaterPlugin.setChannelUrl} across app restarts. Only available for Android and iOS. | `false` | 7.20.0 | | **`allowSetDefaultChannel`** | `boolean` | Allow or disallow the {@link CapacitorUpdaterPlugin.setChannel} method to modify the defaultChannel. When set to `false`, calling `setChannel()` will return an error with code `disabled_by_config`. | `true` | 7.34.0 | | **`defaultChannel`** | `string` | Set the default channel for the app in the config. Case sensitive. This will setting will override the default channel set in the cloud, but will still respect overrides made in the cloud. This requires the channel to allow devices to self dissociate/associate in the channel settings. | `undefined` | 5.5.0 | | **`appId`** | `string` | Configure the app id for the app in the config. | `undefined` | 6.0.0 | | **`keepUrlPathAfterReload`** | `boolean` | Configure the plugin to keep the URL path after a reload. WARNING: When a reload is triggered, ‘window\.history’ will be cleared. | `false` | 6.8.0 | | **`disableJSLogging`** | `boolean` | Disable the JavaScript logging of the plugin. if true, the plugin will not log to the JavaScript console. only the native log will be done | `false` | 7.3.0 | | **`osLogging`** | `boolean` | Enable OS-level logging. When enabled, logs are written to the system log which can be inspected in production builds. - **iOS**: Uses os\_log instead of Swift.print, logs accessible via Console.app or Instruments - **Android**: Logs to Logcat (android.util.Log) When set to false, system logging is disabled on both platforms (only JavaScript console logging will occur if enabled). This is useful for debugging production apps (App Store/TestFlight builds on iOS, or production APKs on Android). | `true` | 8.42.0 | | **`shakeMenu`** | `boolean` | Enable shake gesture to show update menu for debugging/testing purposes | `false` | 7.5.0 | | **`allowShakeChannelSelector`** | `boolean` | Enable the shake gesture to show a channel selector menu for switching between update channels. When enabled AND `shakeMenu` is true, the shake gesture shows a channel selector instead of the default debug menu (Go Home/Reload/Close). After selecting a channel, the app automatically checks for updates and downloads if available. Only works if channels have `allow_self_set` enabled on the backend. Only available for Android and iOS. | `false` | 8.43.0 | ## API Reference [Section titled “API Reference”](#api-reference) * [`notifyAppReady`](#notifyappready) * [`setUpdateUrl`](#setupdateurl) * [`setStatsUrl`](#setstatsurl) * [`setChannelUrl`](#setchannelurl) * [`download`](#download) * [`next`](#next) * [`set`](#set) * [`delete`](#delete) * [`setBundleError`](#setbundleerror) * [`list`](#list) * [`reset`](#reset) * [`current`](#current) * [`reload`](#reload) * [`setMultiDelay`](#setmultidelay) * [`cancelDelay`](#canceldelay) * [`getLatest`](#getlatest) * [`setChannel`](#setchannel) * [`unsetChannel`](#unsetchannel) * [`getChannel`](#getchannel) * [`listChannels`](#listchannels) * [`setCustomId`](#setcustomid) * [`getBuiltinVersion`](#getbuiltinversion) * [`getDeviceId`](#getdeviceid) * [`getPluginVersion`](#getpluginversion) * [`isAutoUpdateEnabled`](#isautoupdateenabled) * [`removeAllListeners`](#removealllisteners) * [`addListener('download')`](#addlistenerdownload-) * [`addListener('noNeedUpdate')`](#addlistenernoneedupdate-) * [`addListener('updateAvailable')`](#addlistenerupdateavailable-) * [`addListener('downloadComplete')`](#addlistenerdownloadcomplete-) * [`addListener('breakingAvailable')`](#addlistenerbreakingavailable-) * [`addListener('majorAvailable')`](#addlistenermajoravailable-) * [`addListener('updateFailed')`](#addlistenerupdatefailed-) * [`addListener('set')`](#addlistenerset-) * [`addListener('setNext')`](#addlistenersetnext-) * [`addListener('downloadFailed')`](#addlistenerdownloadfailed-) * [`addListener('appReloaded')`](#addlistenerappreloaded-) * [`addListener('appReady')`](#addlistenerappready-) * [`addListener('channelPrivate')`](#addlistenerchannelprivate-) * [`addListener('onFlexibleUpdateStateChange')`](#addlisteneronflexibleupdatestatechange-) * [`isAutoUpdateAvailable`](#isautoupdateavailable) * [`getNextBundle`](#getnextbundle) * [`getFailedUpdate`](#getfailedupdate) * [`setShakeMenu`](#setshakemenu) * [`isShakeMenuEnabled`](#isshakemenuenabled) * [`setShakeChannelSelector`](#setshakechannelselector) * [`isShakeChannelSelectorEnabled`](#isshakechannelselectorenabled) * [`getAppId`](#getappid) * [`setAppId`](#setappid) * [`getAppUpdateInfo`](#getappupdateinfo) * [`openAppStore`](#openappstore) * [`performImmediateUpdate`](#performimmediateupdate) * [`startFlexibleUpdate`](#startflexibleupdate) * [`completeFlexibleUpdate`](#completeflexibleupdate) ### notifyAppReady [Section titled “notifyAppReady”](#notifyappready) ```typescript notifyAppReady() => Promise ``` Notify the native layer that JavaScript initialized successfully. **CRITICAL: You must call this method on every app launch to prevent automatic rollback.** This is a simple notification to confirm that your bundle’s JavaScript loaded and executed. The native web server successfully served the bundle files and your JS runtime started. That’s all it checks - nothing more complex. **What triggers rollback:** * NOT calling this method within the timeout (default: 10 seconds) * Complete JavaScript failure (bundle won’t load at all) **What does NOT trigger rollback:** * Runtime errors after initialization (API failures, crashes, etc.) * Network request failures * Application logic errors **IMPORTANT: Call this BEFORE any network requests.** Don’t wait for APIs, data loading, or async operations. Call it as soon as your JavaScript bundle starts executing to confirm the bundle itself is valid. Best practices: * Call immediately in your app entry point (main.js, app component mount, etc.) * Don’t put it after network calls or heavy initialization * Don’t wrap it in try/catch with conditions * Adjust {@link PluginsConfig.CapacitorUpdater.appReadyTimeout} if you need more time **Returns** `Promise` — Always resolves successfully with current bundle info. This method never fails. *** ### setUpdateUrl [Section titled “setUpdateUrl”](#setupdateurl) ```typescript setUpdateUrl(options: UpdateUrl) => Promise ``` Set the update URL for the app dynamically at runtime. This overrides the {@link PluginsConfig.CapacitorUpdater.updateUrl} config value. Requires {@link PluginsConfig.CapacitorUpdater.allowModifyUrl} to be set to `true`. Use {@link PluginsConfig.CapacitorUpdater.persistModifyUrl} to persist this value across app restarts. Otherwise, the URL will reset to the config value on next app launch. **Parameters** | Name | Type | Description | | --------- | ----------- | ------------------------------------------------- | | `options` | `UpdateUrl` | Contains the URL to use for checking for updates. | **Returns** `Promise` — Resolves when the URL is successfully updated. **Since:** 5.4.0 **Throws:** {Error} If `allowModifyUrl` is false or if the operation fails. *** ### setStatsUrl [Section titled “setStatsUrl”](#setstatsurl) ```typescript setStatsUrl(options: StatsUrl) => Promise ``` Set the statistics URL for the app dynamically at runtime. This overrides the {@link PluginsConfig.CapacitorUpdater.statsUrl} config value. Requires {@link PluginsConfig.CapacitorUpdater.allowModifyUrl} to be set to `true`. Pass an empty string to disable statistics gathering entirely. Use {@link PluginsConfig.CapacitorUpdater.persistModifyUrl} to persist this value across app restarts. **Parameters** | Name | Type | Description | | --------- | ---------- | ------------------------------------------------------------------------------ | | `options` | `StatsUrl` | Contains the URL to use for sending statistics, or an empty string to disable. | **Returns** `Promise` — Resolves when the URL is successfully updated. **Since:** 5.4.0 **Throws:** {Error} If `allowModifyUrl` is false or if the operation fails. *** ### setChannelUrl [Section titled “setChannelUrl”](#setchannelurl) ```typescript setChannelUrl(options: ChannelUrl) => Promise ``` Set the channel URL for the app dynamically at runtime. This overrides the {@link PluginsConfig.CapacitorUpdater.channelUrl} config value. Requires {@link PluginsConfig.CapacitorUpdater.allowModifyUrl} to be set to `true`. Use {@link PluginsConfig.CapacitorUpdater.persistModifyUrl} to persist this value across app restarts. Otherwise, the URL will reset to the config value on next app launch. **Parameters** | Name | Type | Description | | --------- | ------------ | ----------------------------------------------- | | `options` | `ChannelUrl` | Contains the URL to use for channel operations. | **Returns** `Promise` — Resolves when the URL is successfully updated. **Since:** 5.4.0 **Throws:** {Error} If `allowModifyUrl` is false or if the operation fails. *** ### download [Section titled “download”](#download) ```typescript download(options: DownloadOptions) => Promise ``` Download a new bundle from the provided URL for later installation. The downloaded bundle is stored locally but not activated. To use it: * Call {@link next} to set it for installation on next app backgrounding/restart * Call {@link set} to activate it immediately (destroys current JavaScript context) The URL should point to a zip file containing either: * Your app files directly in the zip root, or * A single folder containing all your app files The bundle must include an `index.html` file at the root level. For encrypted bundles, provide the `sessionKey` and `checksum` parameters. For multi-file delta updates, provide the `manifest` array. **Parameters** | Name | Type | Description | | --------- | ----------------- | ------------------------------------------------------------- | | `options` | `DownloadOptions` | The {@link DownloadOptions} for downloading a new bundle zip. | **Returns** `Promise` — The {@link BundleInfo} for the downloaded bundle. **Throws:** {Error} If the download fails or the bundle is invalid. **Example** ```ts const bundle = await CapacitorUpdater.download({ url: `https://example.com/versions/${version}/dist.zip`, version: version }); // Bundle is downloaded but not active yet await CapacitorUpdater.next({ id: bundle.id }); // Will activate on next background ``` *** ### next [Section titled “next”](#next) ```typescript next(options: BundleId) => Promise ``` Set the next bundle to be activated when the app backgrounds or restarts. This is the recommended way to apply updates as it doesn’t interrupt the user’s current session. The bundle will be activated when: * The app is backgrounded (user switches away), or * The app is killed and relaunched, or * {@link reload} is called manually Unlike {@link set}, this method does NOT destroy the current JavaScript context immediately. Your app continues running normally until one of the above events occurs. Use {@link setMultiDelay} to add additional conditions before the update is applied. **Parameters** | Name | Type | Description | | --------- | ---------- | ------------------------------------------------------------------------------------------------- | | `options` | `BundleId` | Contains the ID of the bundle to set as next. Use {@link BundleInfo.id} from a downloaded bundle. | **Returns** `Promise` — The {@link BundleInfo} for the specified bundle. **Throws:** {Error} When there is no index.html file inside the bundle folder or the bundle doesn’t exist. *** ### set [Section titled “set”](#set) ```typescript set(options: BundleId) => Promise ``` Set the current bundle and immediately reloads the app. **IMPORTANT: This is a terminal operation that destroys the current JavaScript context.** When you call this method: * The entire JavaScript context is immediately destroyed * The app reloads from a different folder with different files * NO code after this call will execute * NO promises will resolve * NO callbacks will fire * Event listeners registered after this call are unreliable and may never fire The reload happens automatically - you don’t need to do anything else. If you need to preserve state like the current URL path, use the {@link PluginsConfig.CapacitorUpdater.keepUrlPathAfterReload} config option. For other state preservation needs, save your data before calling this method (e.g., to localStorage). **Do not** try to execute additional logic after calling `set()` - it won’t work as expected. **Parameters** | Name | Type | Description | | --------- | ---------- | ------------------------------------------------------------------------- | | `options` | `BundleId` | A {@link BundleId} object containing the new bundle id to set as current. | **Returns** `Promise` — A promise that will never resolve because the JavaScript context is destroyed. **Throws:** {Error} When there is no index.html file inside the bundle folder. *** ### delete [Section titled “delete”](#delete) ```typescript delete(options: BundleId) => Promise ``` Delete a bundle from local storage to free up disk space. You cannot delete: * The currently active bundle * The `builtin` bundle (the version shipped with your app) * The bundle set as `next` (call {@link next} with a different bundle first) Use {@link list} to get all available bundle IDs. **Note:** The bundle ID is NOT the same as the version name. Use the `id` field from {@link BundleInfo}, not the `version` field. **Parameters** | Name | Type | Description | | --------- | ---------- | ------------------------------------------------------------- | | `options` | `BundleId` | A {@link BundleId} object containing the bundle ID to delete. | **Returns** `Promise` — Resolves when the bundle is successfully deleted. **Throws:** {Error} If the bundle is currently in use or doesn’t exist. *** ### setBundleError [Section titled “setBundleError”](#setbundleerror) ```typescript setBundleError(options: BundleId) => Promise ``` Manually mark a bundle as failed/errored in manual update mode. This is useful when you detect that a bundle has critical issues and want to prevent it from being used again. The bundle status will be changed to `error` and the plugin will avoid using this bundle in the future. **Requirements:** * {@link PluginsConfig.CapacitorUpdater.allowManualBundleError} must be set to `true` * Only works in manual update mode (when autoUpdate is disabled) Common use case: After downloading and testing a bundle, you discover it has critical bugs and want to mark it as failed so it won’t be retried. **Parameters** | Name | Type | Description | | --------- | ---------- | ---------------------------------------------------------------------- | | `options` | `BundleId` | A {@link BundleId} object containing the bundle ID to mark as errored. | **Returns** `Promise` — The updated {@link BundleInfo} with status set to `error`. **Since:** 7.20.0 **Throws:** {Error} When the bundle does not exist or `allowManualBundleError` is false. *** ### list [Section titled “list”](#list) ```typescript list(options?: ListOptions | undefined) => Promise ``` Get all locally downloaded bundles stored in your app. This returns all bundles that have been downloaded and are available locally, including: * The currently active bundle * The `builtin` bundle (shipped with your app) * Any downloaded bundles waiting to be activated * Failed bundles (with `error` status) Use this to: * Check available disk space by counting bundles * Delete old bundles with {@link delete} * Monitor bundle download status **Parameters** | Name | Type | Description | | --------- | ------------- | ----------- | | `options` | \`ListOptions | undefined\` | **Returns** `Promise` — A promise containing the array of {@link BundleInfo} objects. **Throws:** {Error} If the operation fails. *** ### reset [Section titled “reset”](#reset) ```typescript reset(options?: ResetOptions | undefined) => Promise ``` Reset the app to a known good bundle. This method helps recover from problematic updates by reverting to either: * The `builtin` bundle (the original version shipped with your app to App Store/Play Store) * The last successfully loaded bundle (most recent bundle that worked correctly) **IMPORTANT: This triggers an immediate app reload, destroying the current JavaScript context.** See {@link set} for details on the implications of this operation. Use cases: * Emergency recovery when an update causes critical issues * Testing rollback functionality * Providing users a “reset to factory” option **Parameters** | Name | Type | Description | | --------- | -------------- | ----------- | | `options` | \`ResetOptions | undefined\` | **Returns** `Promise` — A promise that may never resolve because the app will be reloaded. **Throws:** {Error} If the reset operation fails. *** ### current [Section titled “current”](#current) ```typescript current() => Promise ``` Get information about the currently active bundle. Returns: * `bundle`: The currently active bundle information * `native`: The version of the builtin bundle (the original app version from App/Play Store) If no updates have been applied, `bundle.id` will be `"builtin"`, indicating the app is running the original version shipped with the native app. Use this to: * Display the current version to users * Check if an update is currently active * Compare against available updates * Log the active bundle for debugging **Returns** `Promise` — A promise with the current bundle and native version info. **Throws:** {Error} If the operation fails. *** ### reload [Section titled “reload”](#reload) ```typescript reload() => Promise ``` Manually reload the app to apply a pending update. This triggers the same reload behavior that happens automatically when the app backgrounds. If you’ve called {@link next} to queue an update, calling `reload()` will apply it immediately. **IMPORTANT: This destroys the current JavaScript context immediately.** See {@link set} for details on the implications of this operation. Common use cases: * Applying an update immediately after download instead of waiting for backgrounding * Providing a “Restart now” button to users after an update is ready * Testing update flows during development If no update is pending (no call to {@link next}), this simply reloads the current bundle. **Returns** `Promise` — A promise that may never resolve because the app will be reloaded. **Throws:** {Error} If the reload operation fails. *** ### setMultiDelay [Section titled “setMultiDelay”](#setmultidelay) ```typescript setMultiDelay(options: MultiDelayConditions) => Promise ``` Configure conditions that must be met before a pending update is applied. After calling {@link next} to queue an update, use this method to control when it gets applied. The update will only be installed after ALL specified conditions are satisfied. Available condition types: * `background`: Wait for the app to be backgrounded. Optionally specify duration in milliseconds. * `kill`: Wait for the app to be killed and relaunched (**Note:** Current behavior triggers update immediately on kill, not on next background. This will be fixed in v8.) * `date`: Wait until a specific date/time (ISO 8601 format) * `nativeVersion`: Wait until the native app is updated to a specific version Condition value formats: * `background`: Number in milliseconds (e.g., `"300000"` for 5 minutes), or omit for immediate * `kill`: No value needed * `date`: ISO 8601 date string (e.g., `"2025-12-31T23:59:59Z"`) * `nativeVersion`: Version string (e.g., `"2.0.0"`) **Parameters** | Name | Type | Description | | --------- | ---------------------- | -------------------------------------------------------------- | | `options` | `MultiDelayConditions` | Contains the {@link MultiDelayConditions} array of conditions. | **Returns** `Promise` — Resolves when the delay conditions are set. **Since:** 4.3.0 **Throws:** {Error} If the operation fails or conditions are invalid. **Example** ```ts // Update after user kills app OR after 5 minutes in background await CapacitorUpdater.setMultiDelay({ delayConditions: [ { kind: 'kill' }, { kind: 'background', value: '300000' } ] }); ``` **Example** ```ts // Update after a specific date await CapacitorUpdater.setMultiDelay({ delayConditions: [{ kind: 'date', value: '2025-12-31T23:59:59Z' }] }); ``` **Example** ```ts // Default behavior: update on next background await CapacitorUpdater.setMultiDelay({ delayConditions: [{ kind: 'background' }] }); ``` *** ### cancelDelay [Section titled “cancelDelay”](#canceldelay) ```typescript cancelDelay() => Promise ``` Cancel all delay conditions and apply the pending update immediately. If you’ve set delay conditions with {@link setMultiDelay}, this method clears them and triggers the pending update to be applied on the next app background or restart. This is useful when: * User manually requests to update now (e.g., clicks “Update now” button) * Your app detects it’s a good time to update (e.g., user finished critical task) * You want to override a time-based delay early **Returns** `Promise` — Resolves when the delay conditions are cleared. **Since:** 4.0.0 **Throws:** {Error} If the operation fails. *** ### getLatest [Section titled “getLatest”](#getlatest) ```typescript getLatest(options?: GetLatestOptions | undefined) => Promise ``` Check the update server for the latest available bundle version. This queries your configured update URL (or Capgo backend) to see if a newer bundle is available for download. It does NOT download the bundle automatically. The response includes: * `version`: The latest available version identifier * `url`: Download URL for the bundle (if available) * `breaking`: Whether this update is marked as incompatible (requires native app update) * `message`: Optional message from the server * `manifest`: File list for delta updates (if using multi-file downloads) After receiving the latest version info, you can: 1. Compare it with your current version 2. Download it using {@link download} 3. Apply it using {@link next} or {@link set} **Important: Error handling for “no new version available”** When the device’s current version matches the latest version on the server (i.e., the device is already up-to-date), the server returns a 200 response with `error: "no_new_version_available"` and `message: "No new version available"`. **This causes `getLatest()` to throw an error**, even though this is a normal, expected condition. You should catch this specific error to handle it gracefully: ```typescript try { const latest = await CapacitorUpdater.getLatest(); // New version is available, proceed with download } catch (error) { if (error.message === 'No new version available') { // Device is already on the latest version - this is normal console.log('Already up to date'); } else { // Actual error occurred console.error('Failed to check for updates:', error); } } ``` In this scenario, the server: * Logs the request with a “No new version available” message * Sends a “noNew” stat action to track that the device checked for updates but was already current (done on the backend) **Parameters** | Name | Type | Description | | --------- | ------------------ | ----------- | | `options` | \`GetLatestOptions | undefined\` | **Returns** `Promise` — Information about the latest available bundle version. **Since:** 4.0.0 **Throws:** {Error} Always throws when no new version is available (`error: "no_new_version_available"`), or when the request fails. *** ### setChannel [Section titled “setChannel”](#setchannel) ```typescript setChannel(options: SetChannelOptions) => Promise ``` Assign this device to a specific update channel at runtime. Channels allow you to distribute different bundle versions to different groups of users (e.g., “production”, “beta”, “staging”). This method switches the device to a new channel. **Requirements:** * The target channel must allow self-assignment (configured in your Capgo dashboard or backend) * The backend may accept or reject the request based on channel settings **When to use:** * After the app is ready and the user has interacted (e.g., opted into beta program) * To implement in-app channel switching (beta toggle, tester access, etc.) * For user-driven channel changes **When NOT to use:** * At app boot/initialization - use {@link PluginsConfig.CapacitorUpdater.defaultChannel} config instead * Before user interaction **Important: Listen for the `channelPrivate` event** When a user attempts to set a channel that doesn’t allow device self-assignment, the method will throw an error AND fire a {@link addListener}(‘channelPrivate’) event. You should listen to this event to provide appropriate feedback to users: ```typescript CapacitorUpdater.addListener('channelPrivate', (data) => { console.warn(`Cannot access channel "${data.channel}": ${data.message}`); // Show user-friendly message }); ``` This sends a request to the Capgo backend linking your device ID to the specified channel. **Parameters** | Name | Type | Description | | --------- | ------------------- | ------------------------------------------------------------------------------------------- | | `options` | `SetChannelOptions` | The {@link SetChannelOptions} containing the channel name and optional auto-update trigger. | **Returns** `Promise` — Channel operation result with status and optional error/message. **Since:** 4.7.0 **Throws:** {Error} If the channel doesn’t exist or doesn’t allow self-assignment. *** ### unsetChannel [Section titled “unsetChannel”](#unsetchannel) ```typescript unsetChannel(options: UnsetChannelOptions) => Promise ``` Remove the device’s channel assignment and return to the default channel. This unlinks the device from any specifically assigned channel, causing it to fall back to: * The {@link PluginsConfig.CapacitorUpdater.defaultChannel} if configured, or * Your backend’s default channel for this app Use this when: * Users opt out of beta/testing programs * You want to reset a device to standard update distribution * Testing channel switching behavior **Parameters** | Name | Type | Description | | --------- | --------------------- | ----------- | | `options` | `UnsetChannelOptions` | | **Returns** `Promise` — Resolves when the channel is successfully unset. **Since:** 4.7.0 **Throws:** {Error} If the operation fails. *** ### getChannel [Section titled “getChannel”](#getchannel) ```typescript getChannel() => Promise ``` Get the current channel assigned to this device. Returns information about: * `channel`: The currently assigned channel name (if any) * `allowSet`: Whether the channel allows self-assignment * `status`: Operation status * `error`/`message`: Additional information (if applicable) Use this to: * Display current channel to users (e.g., “You’re on the Beta channel”) * Check if a device is on a specific channel before showing features * Verify channel assignment after calling {@link setChannel} **Returns** `Promise` — The current channel information. **Since:** 4.8.0 **Throws:** {Error} If the operation fails. *** ### listChannels [Section titled “listChannels”](#listchannels) ```typescript listChannels() => Promise ``` Get a list of all channels available for this device to self-assign to. Only returns channels where `allow_self_set` is `true`. These are channels that users can switch to using {@link setChannel} without backend administrator intervention. Each channel includes: * `id`: Unique channel identifier * `name`: Human-readable channel name * `public`: Whether the channel is publicly visible * `allow_self_set`: Always `true` in results (filtered to only self-assignable channels) Use this to: * Build a channel selector UI for users (e.g., “Join Beta” button) * Show available testing/preview channels * Implement channel discovery features **Returns** `Promise` — List of channels the device can self-assign to. **Since:** 7.5.0 **Throws:** {Error} If the operation fails or the request to the backend fails. *** ### setCustomId [Section titled “setCustomId”](#setcustomid) ```typescript setCustomId(options: SetCustomIdOptions) => Promise ``` Set a custom identifier for this device. This allows you to identify devices by your own custom ID (user ID, account ID, etc.) instead of or in addition to the device’s unique hardware ID. The custom ID is sent to your update server and can be used for: * Targeting specific users for updates * Analytics and user tracking * Debugging and support (correlating devices with users) * A/B testing or feature flagging **Persistence:** * When {@link PluginsConfig.CapacitorUpdater.persistCustomId} is `true`, the ID persists across app restarts * When `false`, the ID is only kept for the current session **Clearing the custom ID:** * Pass an empty string `""` to remove any stored custom ID **Parameters** | Name | Type | Description | | --------- | -------------------- | ----------------------------------------------------------------------- | | `options` | `SetCustomIdOptions` | The {@link SetCustomIdOptions} containing the custom identifier string. | **Returns** `Promise` — Resolves immediately (synchronous operation). **Since:** 4.9.0 **Throws:** {Error} If the operation fails. *** ### getBuiltinVersion [Section titled “getBuiltinVersion”](#getbuiltinversion) ```typescript getBuiltinVersion() => Promise ``` Get the builtin bundle version (the original version shipped with your native app). This returns the version of the bundle that was included when the app was installed from the App Store or Play Store. This is NOT the currently active bundle version - use {@link current} for that. Returns: * The {@link PluginsConfig.CapacitorUpdater.version} config value if set, or * The native app version from platform configs (package.json, Info.plist, build.gradle) Use this to: * Display the “factory” version to users * Compare against downloaded bundle versions * Determine if any updates have been applied * Debugging version mismatches **Returns** `Promise` — The builtin bundle version string. **Since:** 5.2.0 *** ### getDeviceId [Section titled “getDeviceId”](#getdeviceid) ```typescript getDeviceId() => Promise ``` Get the unique, privacy-friendly identifier for this device. This ID is used to identify the device when communicating with update servers. It’s automatically generated and stored securely by the plugin. **Privacy & Security characteristics:** * Generated as a UUID (not based on hardware identifiers) * Stored securely in platform-specific secure storage * Android: Android Keystore (persists across app reinstalls on API 23+) * iOS: Keychain with `kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly` * Not synced to cloud (iOS) * Follows Apple and Google privacy best practices * Users can clear it via system settings (Android) or keychain access (iOS) **Persistence:** The device ID persists across app reinstalls to maintain consistent device identity for update tracking and analytics. Use this to: * Debug update delivery issues (check what ID the server sees) * Implement device-specific features * Correlate server logs with specific devices **Returns** `Promise` — The unique device identifier string. **Throws:** {Error} If the operation fails. *** ### getPluginVersion [Section titled “getPluginVersion”](#getpluginversion) ```typescript getPluginVersion() => Promise ``` Get the version of the Capacitor Updater plugin installed in your app. This returns the version of the native plugin code (Android/iOS), which is sent to the update server with each request. This is NOT your app version or bundle version. Use this to: * Debug plugin-specific issues (when reporting bugs) * Verify plugin installation and version * Check compatibility with backend features * Display in debug/about screens **Returns** `Promise` — The Capacitor Updater plugin version string. **Throws:** {Error} If the operation fails. *** ### isAutoUpdateEnabled [Section titled “isAutoUpdateEnabled”](#isautoupdateenabled) ```typescript isAutoUpdateEnabled() => Promise ``` Check if automatic updates are currently enabled. Returns `true` if {@link PluginsConfig.CapacitorUpdater.autoUpdate} is enabled, meaning the plugin will automatically check for, download, and apply updates. Returns `false` if in manual mode, where you control the update flow using {@link getLatest}, {@link download}, {@link next}, and {@link set}. Use this to: * Determine which update flow your app is using * Show/hide manual update UI based on mode * Debug update behavior **Returns** `Promise` — `true` if auto-update is enabled, `false` if in manual mode. **Throws:** {Error} If the operation fails. *** ### removeAllListeners [Section titled “removeAllListeners”](#removealllisteners) ```typescript removeAllListeners() => Promise ``` Remove all event listeners registered for this plugin. This unregisters all listeners added via {@link addListener} for all event types: * `download` * `noNeedUpdate` * `updateAvailable` * `downloadComplete` * `downloadFailed` * `breakingAvailable` / `majorAvailable` * `updateFailed` * `appReloaded` * `appReady` Use this during cleanup (e.g., when unmounting components or closing screens) to prevent memory leaks from lingering event listeners. **Returns** `Promise` — Resolves when all listeners are removed. **Since:** 1.0.0 *** ### addListener(‘download’) [Section titled “addListener(‘download’)”](#addlistenerdownload) ```typescript addListener(eventName: 'download', listenerFunc: (state: DownloadEvent) => void) => Promise ``` Listen for bundle download event in the App. Fires once a download has started, during downloading and when finished. This will return you all download percent during the download **Parameters** | Name | Type | Description | | -------------- | -------------------------------- | ----------- | | `eventName` | `'download'` | | | `listenerFunc` | `(state: DownloadEvent) => void` | | **Returns** `Promise` **Since:** 2.0.11 *** ### addListener(‘noNeedUpdate’) [Section titled “addListener(‘noNeedUpdate’)”](#addlistenernoneedupdate) ```typescript addListener(eventName: 'noNeedUpdate', listenerFunc: (state: NoNeedEvent) => void) => Promise ``` Listen for no need to update event, useful when you want force check every time the app is launched **Parameters** | Name | Type | Description | | -------------- | ------------------------------ | ----------- | | `eventName` | `'noNeedUpdate'` | | | `listenerFunc` | `(state: NoNeedEvent) => void` | | **Returns** `Promise` **Since:** 4.0.0 *** ### addListener(‘updateAvailable’) [Section titled “addListener(‘updateAvailable’)”](#addlistenerupdateavailable) ```typescript addListener(eventName: 'updateAvailable', listenerFunc: (state: UpdateAvailableEvent) => void) => Promise ``` Listen for available update event, useful when you want to force check every time the app is launched **Parameters** | Name | Type | Description | | -------------- | --------------------------------------- | ----------- | | `eventName` | `'updateAvailable'` | | | `listenerFunc` | `(state: UpdateAvailableEvent) => void` | | **Returns** `Promise` **Since:** 4.0.0 *** ### addListener(‘downloadComplete’) [Section titled “addListener(‘downloadComplete’)”](#addlistenerdownloadcomplete) ```typescript addListener(eventName: 'downloadComplete', listenerFunc: (state: DownloadCompleteEvent) => void) => Promise ``` Listen for downloadComplete events. **Parameters** | Name | Type | Description | | -------------- | ---------------------------------------- | ----------- | | `eventName` | `'downloadComplete'` | | | `listenerFunc` | `(state: DownloadCompleteEvent) => void` | | **Returns** `Promise` **Since:** 4.0.0 *** ### addListener(‘breakingAvailable’) [Section titled “addListener(‘breakingAvailable’)”](#addlistenerbreakingavailable) ```typescript addListener(eventName: 'breakingAvailable', listenerFunc: (state: BreakingAvailableEvent) => void) => Promise ``` Listen for breaking update events when the backend flags an update as incompatible with the current app. Emits the same payload as the legacy `majorAvailable` listener. **Parameters** | Name | Type | Description | | -------------- | -------------------------------------- | ----------- | | `eventName` | `'breakingAvailable'` | | | `listenerFunc` | `(state: MajorAvailableEvent) => void` | | **Returns** `Promise` **Since:** 7.22.0 *** ### addListener(‘majorAvailable’) [Section titled “addListener(‘majorAvailable’)”](#addlistenermajoravailable) ```typescript addListener(eventName: 'majorAvailable', listenerFunc: (state: MajorAvailableEvent) => void) => Promise ``` Listen for Major update event in the App, let you know when major update is blocked by setting disableAutoUpdateBreaking **Parameters** | Name | Type | Description | | -------------- | -------------------------------------- | ----------- | | `eventName` | `'majorAvailable'` | | | `listenerFunc` | `(state: MajorAvailableEvent) => void` | | **Returns** `Promise` **Since:** 2.3.0 *** ### addListener(‘updateFailed’) [Section titled “addListener(‘updateFailed’)”](#addlistenerupdatefailed) ```typescript addListener(eventName: 'updateFailed', listenerFunc: (state: UpdateFailedEvent) => void) => Promise ``` Listen for update fail event in the App, let you know when update has fail to install at next app start **Parameters** | Name | Type | Description | | -------------- | ------------------------------------ | ----------- | | `eventName` | `'updateFailed'` | | | `listenerFunc` | `(state: UpdateFailedEvent) => void` | | **Returns** `Promise` **Since:** 2.3.0 *** ### addListener(‘set’) [Section titled “addListener(‘set’)”](#addlistenerset) ```typescript addListener(eventName: 'set', listenerFunc: (state: SetEvent) => void) => Promise ``` Listen for set event in the App, let you know when a bundle has been applied successfully. This event is retained natively until JavaScript consumes it, so if the app reloads before your listener is attached, the last pending `set` event is delivered once the listener subscribes. **Parameters** | Name | Type | Description | | -------------- | --------------------------- | ----------- | | `eventName` | `'set'` | | | `listenerFunc` | `(state: SetEvent) => void` | | **Returns** `Promise` **Since:** 8.43.12 *** ### addListener(‘setNext’) [Section titled “addListener(‘setNext’)”](#addlistenersetnext) ```typescript addListener(eventName: 'setNext', listenerFunc: (state: SetNextEvent) => void) => Promise ``` Listen for set next event in the App, let you know when a bundle is queued as the next bundle to install. **Parameters** | Name | Type | Description | | -------------- | ------------------------------- | ----------- | | `eventName` | `'setNext'` | | | `listenerFunc` | `(state: SetNextEvent) => void` | | **Returns** `Promise` **Since:** 6.14.0 *** ### addListener(‘downloadFailed’) [Section titled “addListener(‘downloadFailed’)”](#addlistenerdownloadfailed) ```typescript addListener(eventName: 'downloadFailed', listenerFunc: (state: DownloadFailedEvent) => void) => Promise ``` Listen for download fail event in the App, let you know when a bundle download has failed **Parameters** | Name | Type | Description | | -------------- | -------------------------------------- | ----------- | | `eventName` | `'downloadFailed'` | | | `listenerFunc` | `(state: DownloadFailedEvent) => void` | | **Returns** `Promise` **Since:** 4.0.0 *** ### addListener(‘appReloaded’) [Section titled “addListener(‘appReloaded’)”](#addlistenerappreloaded) ```typescript addListener(eventName: 'appReloaded', listenerFunc: () => void) => Promise ``` Listen for reload event in the App, let you know when reload has happened **Parameters** | Name | Type | Description | | -------------- | --------------- | ----------- | | `eventName` | `'appReloaded'` | | | `listenerFunc` | `() => void` | | **Returns** `Promise` **Since:** 4.3.0 *** ### addListener(‘appReady’) [Section titled “addListener(‘appReady’)”](#addlistenerappready) ```typescript addListener(eventName: 'appReady', listenerFunc: (state: AppReadyEvent) => void) => Promise ``` Listen for app ready event in the App, let you know when app is ready to use. This event is retained natively until JavaScript consumes it, so it can still be delivered after a reload even if the listener is attached later in app startup. **Parameters** | Name | Type | Description | | -------------- | -------------------------------- | ----------- | | `eventName` | `'appReady'` | | | `listenerFunc` | `(state: AppReadyEvent) => void` | | **Returns** `Promise` **Since:** 5.1.0 *** ### addListener(‘channelPrivate’) [Section titled “addListener(‘channelPrivate’)”](#addlistenerchannelprivate) ```typescript addListener(eventName: 'channelPrivate', listenerFunc: (state: ChannelPrivateEvent) => void) => Promise ``` Listen for channel private event, fired when attempting to set a channel that doesn’t allow device self-assignment. This event is useful for: * Informing users they don’t have permission to switch to a specific channel * Implementing custom error handling for channel restrictions * Logging unauthorized channel access attempts **Parameters** | Name | Type | Description | | -------------- | -------------------------------------- | ----------- | | `eventName` | `'channelPrivate'` | | | `listenerFunc` | `(state: ChannelPrivateEvent) => void` | | **Returns** `Promise` **Since:** 7.34.0 *** ### addListener(‘onFlexibleUpdateStateChange’) [Section titled “addListener(‘onFlexibleUpdateStateChange’)”](#addlisteneronflexibleupdatestatechange) ```typescript addListener(eventName: 'onFlexibleUpdateStateChange', listenerFunc: (state: FlexibleUpdateState) => void) => Promise ``` Listen for flexible update state changes on Android. This event fires during the flexible update download process, providing: * Download progress (bytes downloaded / total bytes) * Installation status changes **Install status values:** * `UNKNOWN` (0): Unknown status * `PENDING` (1): Download pending * `DOWNLOADING` (2): Download in progress * `INSTALLING` (3): Installing the update * `INSTALLED` (4): Update installed (app restart needed) * `FAILED` (5): Update failed * `CANCELED` (6): Update was canceled * `DOWNLOADED` (11): Download complete, ready to install When status is `DOWNLOADED`, you should prompt the user and call {@link completeFlexibleUpdate} to finish the installation. **Parameters** | Name | Type | Description | | -------------- | -------------------------------------- | ----------- | | `eventName` | `'onFlexibleUpdateStateChange'` | | | `listenerFunc` | `(state: FlexibleUpdateState) => void` | | **Returns** `Promise` **Since:** 8.0.0 *** ### isAutoUpdateAvailable [Section titled “isAutoUpdateAvailable”](#isautoupdateavailable) ```typescript isAutoUpdateAvailable() => Promise ``` Check if the auto-update feature is available (not disabled by custom server configuration). Returns `false` when a custom `updateUrl` is configured, as this typically indicates you’re using a self-hosted update server that may not support all auto-update features. Returns `true` when using the default Capgo backend or when the feature is available. This is different from {@link isAutoUpdateEnabled}: * `isAutoUpdateEnabled()`: Checks if auto-update MODE is turned on/off * `isAutoUpdateAvailable()`: Checks if auto-update is SUPPORTED with your current configuration **Returns** `Promise` — `false` when custom updateUrl is set, `true` otherwise. **Throws:** {Error} If the operation fails. *** ### getNextBundle [Section titled “getNextBundle”](#getnextbundle) ```typescript getNextBundle() => Promise ``` Get information about the bundle queued to be activated on next reload. Returns: * {@link BundleInfo} object if a bundle has been queued via {@link next} * `null` if no update is pending This is useful to: * Check if an update is waiting to be applied * Display “Update pending” status to users * Show version info of the queued update * Decide whether to show a “Restart to update” prompt The queued bundle will be activated when: * The app is backgrounded (default behavior) * The app is killed and restarted * {@link reload} is called manually * Delay conditions set by {@link setMultiDelay} are met **Returns** `Promise` — The pending bundle info, or `null` if none is queued. **Since:** 6.8.0 **Throws:** {Error} If the operation fails. *** ### getFailedUpdate [Section titled “getFailedUpdate”](#getfailedupdate) ```typescript getFailedUpdate() => Promise ``` Retrieve information about the most recent bundle that failed to load. When a bundle fails to load (e.g., JavaScript errors prevent initialization, missing files), the plugin automatically rolls back and stores information about the failure. This method retrieves that failure information. **IMPORTANT: The stored value is cleared after being retrieved once.** Calling this method multiple times will only return the failure info on the first call, then `null` on subsequent calls until another failure occurs. Returns: * {@link UpdateFailedEvent} with bundle info if a failure was recorded * `null` if no failure has occurred or if it was already retrieved Use this to: * Show users why an update failed * Log failure information for debugging * Implement custom error handling/reporting * Display rollback notifications **Returns** `Promise` — The failed update info (cleared after first retrieval), or `null`. **Since:** 7.22.0 **Throws:** {Error} If the operation fails. *** ### setShakeMenu [Section titled “setShakeMenu”](#setshakemenu) ```typescript setShakeMenu(options: SetShakeMenuOptions) => Promise ``` Enable or disable the shake gesture menu for debugging and testing. When enabled, users can shake their device to open a debug menu that shows: * Current bundle information * Available bundles * Options to switch bundles manually * Update status This is useful during development and testing to: * Quickly test different bundle versions * Debug update flows * Switch between production and test bundles * Verify bundle installations **Important:** Disable this in production builds or only enable for internal testers. Can also be configured via {@link PluginsConfig.CapacitorUpdater.shakeMenu}. **Parameters** | Name | Type | Description | | --------- | --------------------- | ----------- | | `options` | `SetShakeMenuOptions` | | **Returns** `Promise` — Resolves when the setting is applied. **Since:** 7.5.0 **Throws:** {Error} If the operation fails. *** ### isShakeMenuEnabled [Section titled “isShakeMenuEnabled”](#isshakemenuenabled) ```typescript isShakeMenuEnabled() => Promise ``` Check if the shake gesture debug menu is currently enabled. Returns the current state of the shake menu feature that can be toggled via {@link setShakeMenu} or configured via {@link PluginsConfig.CapacitorUpdater.shakeMenu}. Use this to: * Check if debug features are enabled * Show/hide debug settings UI * Verify configuration during testing **Returns** `Promise` — Object with `enabled: true` or `enabled: false`. **Since:** 7.5.0 **Throws:** {Error} If the operation fails. *** ### setShakeChannelSelector [Section titled “setShakeChannelSelector”](#setshakechannelselector) ```typescript setShakeChannelSelector(options: SetShakeChannelSelectorOptions) => Promise ``` Enable or disable the shake channel selector at runtime. When enabled AND shakeMenu is true, shaking the device shows a channel selector instead of the debug menu. This allows users to switch between update channels by shaking their device. After selecting a channel, the app automatically checks for updates and downloads if available. Can also be configured via {@link PluginsConfig.CapacitorUpdater.allowShakeChannelSelector}. **Parameters** | Name | Type | Description | | --------- | -------------------------------- | ----------- | | `options` | `SetShakeChannelSelectorOptions` | | **Returns** `Promise` — Resolves when the setting is applied. **Since:** 8.43.0 **Throws:** {Error} If the operation fails. *** ### isShakeChannelSelectorEnabled [Section titled “isShakeChannelSelectorEnabled”](#isshakechannelselectorenabled) ```typescript isShakeChannelSelectorEnabled() => Promise ``` Check if the shake channel selector is currently enabled. Returns the current state of the shake channel selector feature that can be toggled via {@link setShakeChannelSelector} or configured via {@link PluginsConfig.CapacitorUpdater.allowShakeChannelSelector}. **Returns** `Promise` — Object with `enabled: true` or `enabled: false`. **Since:** 8.43.0 **Throws:** {Error} If the operation fails. *** ### getAppId [Section titled “getAppId”](#getappid) ```typescript getAppId() => Promise ``` Get the currently configured App ID used for update server communication. Returns the App ID that identifies this app to the update server. This can be: * The value set via {@link setAppId}, or * The {@link PluginsConfig.CapacitorUpdater.appId} config value, or * The default app identifier from your native app configuration Use this to: * Verify which App ID is being used for updates * Debug update delivery issues * Display app configuration in debug screens * Confirm App ID after calling {@link setAppId} **Returns** `Promise` — Object containing the current `appId` string. **Since:** 7.14.0 **Throws:** {Error} If the operation fails. *** ### setAppId [Section titled “setAppId”](#setappid) ```typescript setAppId(options: SetAppIdOptions) => Promise ``` Dynamically change the App ID used for update server communication. This overrides the App ID used to identify your app to the update server, allowing you to switch between different app configurations at runtime (e.g., production vs staging app IDs, or multi-tenant configurations). **Requirements:** * {@link PluginsConfig.CapacitorUpdater.allowModifyAppId} must be set to `true` **Important considerations:** * Changing the App ID will affect which updates this device receives * The new App ID must exist on your update server * This is primarily for advanced use cases (multi-tenancy, environment switching) * Most apps should use the config-based {@link PluginsConfig.CapacitorUpdater.appId} instead **Parameters** | Name | Type | Description | | --------- | ----------------- | ----------- | | `options` | `SetAppIdOptions` | | **Returns** `Promise` — Resolves when the App ID is successfully changed. **Since:** 7.14.0 **Throws:** {Error} If `allowModifyAppId` is false or the operation fails. *** ### getAppUpdateInfo [Section titled “getAppUpdateInfo”](#getappupdateinfo) ```typescript getAppUpdateInfo(options?: GetAppUpdateInfoOptions | undefined) => Promise ``` Get information about the app’s availability in the App Store or Play Store. This method checks the native app stores to see if a newer version of the app is available for download. This is different from Capgo’s OTA updates - this checks for native app updates that require going through the app stores. **Platform differences:** * **Android**: Uses Play Store’s In-App Updates API for accurate update information * **iOS**: Queries the App Store lookup API (requires country code for accurate results) **Returns information about:** * Current installed version * Available version in the store (if any) * Whether an update is available * Update priority (Android only) * Whether immediate/flexible updates are allowed (Android only) Use this to: * Check if users need to update from the app store * Show “Update Available” prompts for native updates * Implement version gating (require minimum native version) * Combine with Capgo OTA updates for a complete update strategy **Parameters** | Name | Type | Description | | --------- | ------------------------- | ----------- | | `options` | \`GetAppUpdateInfoOptions | undefined\` | **Returns** `Promise` — Information about the current and available app versions. **Since:** 8.0.0 **Throws:** {Error} If the operation fails or store information is unavailable. *** ### openAppStore [Section titled “openAppStore”](#openappstore) ```typescript openAppStore(options?: OpenAppStoreOptions | undefined) => Promise ``` Open the app’s page in the App Store or Play Store. This navigates the user to your app’s store listing where they can manually update the app. Use this as a fallback when in-app updates are not available or when the user needs to update on iOS. **Platform behavior:** * **Android**: Opens Play Store to the app’s page * **iOS**: Opens App Store to the app’s page **Customization options:** * `appId`: Specify a custom App Store ID (iOS) - useful for opening a different app’s page * `packageName`: Specify a custom package name (Android) - useful for opening a different app’s page **Parameters** | Name | Type | Description | | --------- | --------------------- | ----------- | | `options` | \`OpenAppStoreOptions | undefined\` | **Returns** `Promise` — Resolves when the store is opened. **Since:** 8.0.0 **Throws:** {Error} If the store cannot be opened. *** ### performImmediateUpdate [Section titled “performImmediateUpdate”](#performimmediateupdate) ```typescript performImmediateUpdate() => Promise ``` Perform an immediate in-app update on Android. This triggers Google Play’s immediate update flow, which: 1. Shows a full-screen update UI 2. Downloads and installs the update 3. Restarts the app automatically The user cannot continue using the app until the update is complete. This is ideal for critical updates that must be installed immediately. **Requirements:** * Android only (throws error on iOS) * An update must be available (check with {@link getAppUpdateInfo} first) * The update must allow immediate updates (`immediateUpdateAllowed: true`) **User experience:** * Full-screen blocking UI * Progress shown during download * App automatically restarts after installation **Returns** `Promise` — Result indicating success, cancellation, or failure. **Since:** 8.0.0 **Throws:** {Error} If not on Android, no update is available, or immediate updates not allowed. *** ### startFlexibleUpdate [Section titled “startFlexibleUpdate”](#startflexibleupdate) ```typescript startFlexibleUpdate() => Promise ``` Start a flexible in-app update on Android. This triggers Google Play’s flexible update flow, which: 1. Downloads the update in the background 2. Allows the user to continue using the app 3. Notifies when download is complete 4. Requires calling {@link completeFlexibleUpdate} to install Monitor the download progress using the `onFlexibleUpdateStateChange` listener. **Requirements:** * Android only (throws error on iOS) * An update must be available (check with {@link getAppUpdateInfo} first) * The update must allow flexible updates (`flexibleUpdateAllowed: true`) **Typical flow:** 1. Call `startFlexibleUpdate()` to begin download 2. Listen to `onFlexibleUpdateStateChange` for progress 3. When status is `DOWNLOADED`, prompt user to restart 4. Call `completeFlexibleUpdate()` to install and restart **Returns** `Promise` — Result indicating the update was started, cancelled, or failed. **Since:** 8.0.0 **Throws:** {Error} If not on Android, no update is available, or flexible updates not allowed. *** ### completeFlexibleUpdate [Section titled “completeFlexibleUpdate”](#completeflexibleupdate) ```typescript completeFlexibleUpdate() => Promise ``` Complete a flexible in-app update on Android. After a flexible update has been downloaded (status `DOWNLOADED` in `onFlexibleUpdateStateChange`), call this method to install the update and restart the app. **Important:** This will immediately restart the app. Make sure to: * Save any user data before calling * Prompt the user before restarting * Only call when the download status is `DOWNLOADED` **Returns** `Promise` — Resolves when the update installation begins (app will restart). **Since:** 8.0.0 **Throws:** {Error} If not on Android or no downloaded update is pending. *** # Capacitor Plugins by Capgo > Explore our comprehensive collection of Capacitor plugins to extend your app's native capabilities with powerful features. Welcome to the Capgo Capacitor Plugins collection. This landing page is generated from the live plugin registry plus the docs tree so newly documented plugins show up here automatically. ## Capgo Cloud - Live Updates [Section titled “Capgo Cloud - Live Updates”](#capgo-cloud---live-updates) [Capacitor Updater ](/docs/plugins/updater/)The core plugin powering Capgo Cloud. Deliver instant updates to your Capacitor apps without waiting for app store review. The Updater plugin is the foundation of Capgo Cloud and lets you: * Deploy JavaScript, HTML, CSS, and asset changes in minutes. * Roll out updates to targeted user groups with channels. * Monitor adoption and failure signals from the Capgo console. * Secure releases with encryption and code signing. ## Plugin Directory [Section titled “Plugin Directory”](#plugin-directory) 124 plugins currently resolve from the live Capgo registry. Dedicated docs open when available, and repository links remain visible for the rest. [Accelerometer ](https://github.com/Cap-go/capacitor-accelerometer/)Read device accelerometer for motion detection and orientation tracking Opens the plugin repository until a dedicated docs page is available. [AdMob ](https://github.com/Cap-go/capacitor-admob/)Monetize your app with Google AdMob banner, interstitial, and rewarded ads Opens the plugin repository until a dedicated docs page is available. [Age Range ](https://github.com/Cap-go/capacitor-age-range/)Cross-platform age range detection using Google Play Age Signals (Android) and Apple DeclaredAgeRange (iOS) Opens the plugin repository until a dedicated docs page is available. [Age Signals ](https://github.com/Cap-go/capacitor-android-age-signals/)Google Play Age Signals API wrapper - detect supervised accounts and verified users Opens the plugin repository until a dedicated docs page is available. [Alarm ](https://github.com/Cap-go/capacitor-alarm/)Schedule native alarms and notifications even when app is closed Opens the plugin repository until a dedicated docs page is available. [Android Inline Install ](https://github.com/Cap-go/capacitor-android-inline-install/)Install app updates directly within the app without leaving to Play Store Opens the plugin repository until a dedicated docs page is available. [Android Kiosk ](https://github.com/Cap-go/capacitor-android-kiosk/)Lock Android devices into kiosk mode with launcher functionality and hardware key control Opens the plugin repository until a dedicated docs page is available. [Android SMS Retriever ](https://github.com/Cap-go/capacitor-android-sms-retriever/)Read one app-targeted verification SMS without SMS permissions and request SIM phone number hints on Android Opens the plugin repository until a dedicated docs page is available. [App Attest ](https://github.com/Cap-go/capacitor-app-attest/)Capacitor plugin for cross-platform device attestation using Apple App Attest and Google Play Integrity Standard Opens the plugin repository until a dedicated docs page is available. [App Tracking Transparency ](https://github.com/Cap-go/capacitor-app-tracking-transparency/)Request and check iOS App Tracking Transparency permission for IDFA access Opens the plugin repository until a dedicated docs page is available. [AppInsights ](https://github.com/Cap-go/capacitor-appinsights/)Track app usage, performance metrics, and user behavior with Apptopia AppInsights Opens the plugin repository until a dedicated docs page is available. [AppsFlyer ](https://github.com/Cap-go/capacitor-appsflyer/)Add AppsFlyer attribution, analytics, deferred deep links, and OneLink support to your Capacitor app Opens the plugin repository until a dedicated docs page is available. [Audio Recorder ](https://github.com/Cap-go/capacitor-audio-recorder/)Record audio on iOS, Android, and Web with simple controls and formats Opens the plugin repository until a dedicated docs page is available. [Audio Session ](https://github.com/Cap-go/capacitor-audiosession/)Configure iOS audio session for background playback, mixing, and routing control Opens the plugin repository until a dedicated docs page is available. [Autofill Save Password ](https://github.com/Cap-go/capacitor-autofill-save-password/)Prompt users to save passwords to device autofill for seamless login experience Opens the plugin repository until a dedicated docs page is available. [Background Geolocation ](https://github.com/Cap-go/capacitor-background-geolocation/)Accurate background location tracking with native iOS and Android geofencing plus transition webhooks Opens the plugin repository until a dedicated docs page is available. [Barometer ](https://github.com/Cap-go/capacitor-barometer/)Access device barometer for atmospheric pressure and altitude readings Opens the plugin repository until a dedicated docs page is available. [Bluetooth Low Energy ](https://github.com/Cap-go/capacitor-bluetooth-low-energy/)Full-featured BLE plugin for scanning, connecting, reading, writing, and receiving notifications from Bluetooth devices Opens the plugin repository until a dedicated docs page is available. [Brightness ](https://github.com/Cap-go/capacitor-brightness/)Control device screen brightness programmatically with support for app-specific and system-wide control Opens the plugin repository until a dedicated docs page is available. [Camera Preview ](https://github.com/Cap-go/capacitor-camera-preview/)Display live camera feed as overlay with customizable controls and capture capabilities Opens the plugin repository until a dedicated docs page is available. [Capacitor+ Core ](https://github.com/Cap-go/capacitor-plus/)Capacitor+ is an automated, always-synced fork of Capacitor with merged community PRs and rapid releases Opens the plugin repository until a dedicated docs page is available. [Compass ](https://github.com/Cap-go/capacitor-compass/)Read device compass heading in degrees with continuous updates and permission handling Opens the plugin repository until a dedicated docs page is available. [Contacts ](https://github.com/Cap-go/capacitor-contacts/)Access and manage device contacts with read and write capabilities Opens the plugin repository until a dedicated docs page is available. [Contentsquare ](https://github.com/Cap-go/capacitor-contentsquare/)Integrate Contentsquare mobile analytics, consent gating, screen tracking, transactions, and session replay controls in Capacitor Opens the plugin repository until a dedicated docs page is available. [Crisp ](https://github.com/Cap-go/capacitor-crisp/)Integrate Crisp live chat and customer support directly into your mobile app Opens the plugin repository until a dedicated docs page is available. [Data Storage ](https://github.com/Cap-go/capacitor-data-storage-sqlite/)Store data locally using SQLite database with simple key-value API and encryption support Opens the plugin repository until a dedicated docs page is available. [Document Scanner ](https://github.com/Cap-go/capacitor-document-scanner/)Scan documents with auto edge detection, perspective correction, and PDF export Opens the plugin repository until a dedicated docs page is available. [Downloader ](https://github.com/Cap-go/capacitor-downloader/)Download large files in background with progress tracking and pause/resume support Opens the plugin repository until a dedicated docs page is available. [Electron Updater ](https://github.com/Cap-go/electron-updater/)OTA live updates for Electron apps with the same API surface as capacitor-updater Opens the plugin repository until a dedicated docs page is available. [Env ](https://github.com/Cap-go/capacitor-env/)Securely manage environment variables and configuration across different build environments Opens the plugin repository until a dedicated docs page is available. [Facebook Analytics ](https://github.com/Cap-go/capacitor-facebook-analytics/)Meta/Facebook App Events analytics with standard events, purchase logging, currency parameters, and advertiser tracking controls Opens the plugin repository until a dedicated docs page is available. [Fast SQL ](https://github.com/Cap-go/capacitor-fast-sql/)High-performance native SQLite with custom protocol for efficient sync operations and IndexedDB replacement Opens the plugin repository until a dedicated docs page is available. [FFmpeg ](https://github.com/Cap-go/capacitor-ffmpeg/)Video encoding and processing powered by FFmpeg for compression and conversion Opens the plugin repository until a dedicated docs page is available. [File ](https://github.com/Cap-go/capacitor-file/)Full-featured file system plugin for reading, writing, and managing files and directories Opens the plugin repository until a dedicated docs page is available. [File Compressor ](https://github.com/Cap-go/capacitor-file-compressor/)Capacitor plugin for efficient image compression supporting PNG, JPEG, and WebP formats across iOS, Android, and Web platforms Opens the plugin repository until a dedicated docs page is available. [File Picker ](https://github.com/Cap-go/capacitor-file-picker/)Pick files, images, videos, and directories with full native support for iOS and Android including HEIC conversion Opens the plugin repository until a dedicated docs page is available. [File Sharer ](https://github.com/Cap-go/capacitor-file-sharer/)Share and save files from base64 data or local paths across Android, iOS, and Web Opens the plugin repository until a dedicated docs page is available. [Firebase Analytics ](https://github.com/Cap-go/capacitor-firebase/tree/main/packages/analytics)Capacitor plugin for Firebase Analytics Opens the plugin repository until a dedicated docs page is available. [Firebase App ](https://github.com/Cap-go/capacitor-firebase/tree/main/packages/app)Capacitor plugin for Firebase App Opens the plugin repository until a dedicated docs page is available. [Firebase App Check ](https://github.com/Cap-go/capacitor-firebase/tree/main/packages/app-check)Capacitor plugin for Firebase App Check Opens the plugin repository until a dedicated docs page is available. [Firebase Authentication ](https://github.com/Cap-go/capacitor-firebase/tree/main/packages/authentication)Capacitor plugin for Firebase Authentication Opens the plugin repository until a dedicated docs page is available. [Firebase Crashlytics ](https://github.com/Cap-go/capacitor-firebase/tree/main/packages/crashlytics)Capacitor plugin for Firebase Crashlytics Opens the plugin repository until a dedicated docs page is available. [Firebase Firestore ](https://github.com/Cap-go/capacitor-firebase/tree/main/packages/firestore)Capacitor plugin for Firebase Cloud Firestore Opens the plugin repository until a dedicated docs page is available. [Firebase Functions ](https://github.com/Cap-go/capacitor-firebase/tree/main/packages/functions)Capacitor plugin for Firebase Cloud Functions Opens the plugin repository until a dedicated docs page is available. [Firebase Messaging ](https://github.com/Cap-go/capacitor-firebase/tree/main/packages/messaging)Capacitor plugin for Firebase Cloud Messaging (FCM) Opens the plugin repository until a dedicated docs page is available. [Firebase Performance ](https://github.com/Cap-go/capacitor-firebase/tree/main/packages/performance)Capacitor plugin for Firebase Performance Monitoring Opens the plugin repository until a dedicated docs page is available. [Firebase Remote Config ](https://github.com/Cap-go/capacitor-firebase/tree/main/packages/remote-config)Capacitor plugin for Firebase Remote Config Opens the plugin repository until a dedicated docs page is available. [Firebase Storage ](https://github.com/Cap-go/capacitor-firebase/tree/main/packages/storage)Capacitor plugin for Firebase Cloud Storage Opens the plugin repository until a dedicated docs page is available. [Flash ](https://github.com/Cap-go/capacitor-flash/)Control device flashlight and torch with simple on/off toggle functionality Opens the plugin repository until a dedicated docs page is available. [GTM ](https://github.com/Cap-go/capacitor-gtm/)Google Tag Manager integration for analytics and tracking Opens the plugin repository until a dedicated docs page is available. [Health ](https://github.com/Cap-go/capacitor-health/)Access health and fitness data from native health platforms Opens the plugin repository until a dedicated docs page is available. [iBeacon ](https://github.com/Cap-go/capacitor-ibeacon/)iBeacon plugin for Capacitor - proximity detection and beacon region monitoring Opens the plugin repository until a dedicated docs page is available. [In App Browser ](https://github.com/Cap-go/capacitor-inappbrowser/)Open web pages in a customizable in-app browser without leaving your application Opens the plugin repository until a dedicated docs page is available. [In App Review ](https://github.com/Cap-go/capacitor-in-app-review/)Prompt users to submit app store ratings and reviews without leaving your app using native iOS and Android APIs Opens the plugin repository until a dedicated docs page is available. [Incoming Call Kit ](https://github.com/Cap-go/capacitor-incoming-call-kit/)Present native incoming-call UI with iOS CallKit and Android full-screen notifications Opens the plugin repository until a dedicated docs page is available. [Indicator ](https://github.com/Cap-go/capacitor-home-indicator/)Hide or show iOS home indicator for fullscreen and immersive app experiences Opens the plugin repository until a dedicated docs page is available. [Install Referrer ](https://github.com/Cap-go/capacitor-install-referrer/)Read Google Play install referrer data and Apple AdServices attribution from Capacitor Opens the plugin repository until a dedicated docs page is available. [Intent Launcher ](https://github.com/Cap-go/capacitor-intent-launcher/)Launch Android intents, open system settings, and interact with other apps using the Intent system Opens the plugin repository until a dedicated docs page is available. [Intercom ](https://github.com/Cap-go/capacitor-intercom/)Integrate Intercom live chat, help center, and support workflows in your Capacitor app Opens the plugin repository until a dedicated docs page is available. [Intune ](https://github.com/Cap-go/capacitor-intune/)Microsoft Intune MAM, app protection policy, app config, and MSAL authentication for Capacitor Opens the plugin repository until a dedicated docs page is available. [Is Root ](https://github.com/Cap-go/capacitor-is-root/)Detect rooted Android or jailbroken iOS devices to enhance app security Opens the plugin repository until a dedicated docs page is available. [IVS Player ](https://github.com/Cap-go/capacitor-ivs-player/)Stream ultra-low latency live video using Amazon Interactive Video Service (IVS) Opens the plugin repository until a dedicated docs page is available. [JW Player ](https://github.com/Cap-go/capacitor-jw-player/)Embed JW Player for professional video streaming with ads and analytics support Opens the plugin repository until a dedicated docs page is available. [Keep Awake ](https://github.com/Cap-go/capacitor-keep-awake/)Prevent device screen from dimming or sleeping for video players, navigation, and presentations Opens the plugin repository until a dedicated docs page is available. [Launch Navigator ](https://github.com/Cap-go/capacitor-launch-navigator/)Open navigation apps like Google Maps or Apple Maps with directions to destinations Opens the plugin repository until a dedicated docs page is available. [Light Sensor ](https://github.com/Cap-go/capacitor-light-sensor/)Access the ambient light sensor to measure illuminance levels in lux with real-time updates Opens the plugin repository until a dedicated docs page is available. [Live Activities ](https://github.com/Cap-go/capacitor-live-activities/)Manage iOS Live Activities and Dynamic Island layouts from Capacitor with JSON-driven templates Opens the plugin repository until a dedicated docs page is available. [Live Reload ](https://github.com/Cap-go/capacitor-live-reload/)Connect to your dev server for instant hot reloading during development Opens the plugin repository until a dedicated docs page is available. [LLM ](https://github.com/Cap-go/capacitor-llm/)Run Large Language Models locally on-device with Apple Intelligence and MLX support Opens the plugin repository until a dedicated docs page is available. [Media Session ](https://github.com/Cap-go/capacitor-media-session/)Control media playback from lock screen and notification center Opens the plugin repository until a dedicated docs page is available. [MQTT ](https://github.com/Cap-go/capacitor-mqtt/)MQTT support for real-time messaging across iOS, Android, and Web. Opens the plugin repository until a dedicated docs page is available. [Mute ](https://github.com/Cap-go/capacitor-mute/)Detect device mute switch state for iOS devices to handle audio playback appropriately Opens the plugin repository until a dedicated docs page is available. [Mux Player ](https://github.com/Cap-go/capacitor-mux-player/)Stream adaptive bitrate video with Mux player for optimized playback quality Opens the plugin repository until a dedicated docs page is available. [Native Audio ](https://github.com/Cap-go/capacitor-native-audio/)Play short audio files with low latency using native audio engine for games and apps Opens the plugin repository until a dedicated docs page is available. [Native Biometric ](https://github.com/Cap-go/capacitor-native-biometric/)Secure authentication using Face ID, Touch ID, and Android biometric APIs Opens the plugin repository until a dedicated docs page is available. [Native Geocoder ](https://github.com/Cap-go/capacitor-nativegeocoder/)Convert addresses to coordinates and coordinates to addresses using native geocoding Opens the plugin repository until a dedicated docs page is available. [Native Market ](https://github.com/Cap-go/capacitor-native-market/)Deep link users directly to your app page on Google Play Store or Apple App Store Opens the plugin repository until a dedicated docs page is available. [Native Navigation ](https://github.com/Cap-go/capacitor-native-navigation/)Render native navbars, tabbars, and transition shells over a full-screen Capacitor WebView Opens the plugin repository until a dedicated docs page is available. [Native Purchases ](https://github.com/Cap-go/capacitor-native-purchases/)Implement native in-app purchases and subscriptions for iOS and Android with simple API Opens the plugin repository until a dedicated docs page is available. [Navigation Bar ](https://github.com/Cap-go/capacitor-navigation-bar/)Customize Android navigation bar color and visibility for immersive UI experiences Opens the plugin repository until a dedicated docs page is available. [NFC ](https://github.com/Cap-go/capacitor-nfc/)Native NFC tag discovery, reading and writing for Capacitor apps on iOS and Android Opens the plugin repository until a dedicated docs page is available. [Passkey ](https://github.com/Cap-go/capacitor-passkey/)Keep browser-style WebAuthn code in Capacitor while native passkey calls and host patching are handled for you Opens the plugin repository until a dedicated docs page is available. [Pay ](https://github.com/Cap-go/capacitor-pay/)Accept payments with Apple Pay and Google Pay for seamless checkout experience Opens the plugin repository until a dedicated docs page is available. [PDF Generator ](https://github.com/Cap-go/capacitor-pdf-generator/)Create PDF documents from HTML templates for invoices, reports, and receipts Opens the plugin repository until a dedicated docs page is available. [Pedometer ](https://github.com/Cap-go/capacitor-pedometer/)Track steps, distance, pace, cadence, and floors with device pedometer sensors Opens the plugin repository until a dedicated docs page is available. [Persistent Account ](https://github.com/Cap-go/capacitor-persistent-account/)Preserve user authentication and account data across app reinstalls and updates Opens the plugin repository until a dedicated docs page is available. [Persona ](https://github.com/Cap-go/capacitor-persona/)Launch Persona identity verification inquiries with native iOS and Android SDKs Opens the plugin repository until a dedicated docs page is available. [Photo Library ](https://github.com/Cap-go/capacitor-photo-library/)Browse, save, and manage photos and videos in device photo library with permissions Opens the plugin repository until a dedicated docs page is available. [Printer ](https://github.com/Cap-go/capacitor-printer/)Capacitor plugin for printing documents, HTML, PDFs, images and web views Opens the plugin repository until a dedicated docs page is available. [Privacy Screen ](https://github.com/Cap-go/capacitor-privacy-screen/)Protect app content in Android screenshots and obscure the iOS app switcher snapshot Opens the plugin repository until a dedicated docs page is available. [Proximity ](https://github.com/Cap-go/capacitor-proximity/)Enable native proximity monitoring so your app can react when the device is near a face, hand, or surface Opens the plugin repository until a dedicated docs page is available. [Purchases ](https://github.com/RevenueCat/purchases-capacitor/)Implement in-app subscriptions and purchases with RevenueCat SDK for cross-platform monetization Opens the plugin repository until a dedicated docs page is available. [RealtimeKit ](https://github.com/Cap-go/capacitor-realtimekit/)Cloudflare Calls integration with built-in UI for video meetings and real-time communication Opens the plugin repository until a dedicated docs page is available. [Ricoh360 Camera ](https://github.com/Cap-go/capacitor-ricoh360-camera-plugin/)Control Ricoh Theta 360-degree cameras for immersive panoramic photography Opens the plugin repository until a dedicated docs page is available. [RudderStack ](https://github.com/Cap-go/capacitor-rudderstack/)RudderStack analytics, identity resolution, screen tracking, and delivery controls for Capacitor Opens the plugin repository until a dedicated docs page is available. [Screen Orientation ](https://github.com/Cap-go/capacitor-screen-orientation/)Screen orientation plugin with support for bypassing orientation lock Opens the plugin repository until a dedicated docs page is available. [Screen Recorder ](https://github.com/Cap-go/capacitor-screen-recorder/)Capture screen recordings with audio for tutorials, demos, and bug reports Opens the plugin repository until a dedicated docs page is available. [Shake ](https://github.com/Cap-go/capacitor-shake/)Detect shake gestures on device for triggering actions like undo or feedback Opens the plugin repository until a dedicated docs page is available. [Share Target ](https://github.com/Cap-go/capacitor-share-target/)Receive shared content from other apps - text, images, and files Opens the plugin repository until a dedicated docs page is available. [SIM ](https://github.com/Cap-go/capacitor-sim/)Retrieve SIM card information including carrier name, country code, and phone number Opens the plugin repository until a dedicated docs page is available. [Social Login ](https://github.com/Cap-go/capacitor-social-login/)Authenticate users with Google, Facebook, and Apple Sign-In for easy social login Opens the plugin repository until a dedicated docs page is available. [Speech Recognition ](https://github.com/Cap-go/capacitor-speech-recognition/)Natural, low-latency speech recognition with streaming partial results and cross-platform parity Opens the plugin repository until a dedicated docs page is available. [Speech Synthesis ](https://github.com/Cap-go/capacitor-speech-synthesis/)Synthesize speech from text with full control over language, voice, pitch, rate, and volume. Opens the plugin repository until a dedicated docs page is available. [SSL Pinning ](https://github.com/Cap-go/capacitor-ssl-pinning/)Pin HTTPS connections to bundled certificates for CapacitorHttp on iOS and Android Opens the plugin repository until a dedicated docs page is available. [Streamcall ](https://github.com/Cap-go/capacitor-streamcall/)Integrate video calling and live streaming with Stream SDK for real-time communication Opens the plugin repository until a dedicated docs page is available. [Text Interaction ](https://github.com/Cap-go/capacitor-textinteraction/)Enable advanced text selection, copy-paste, and interaction features in web views Opens the plugin repository until a dedicated docs page is available. [Twilio Video ](https://github.com/Cap-go/capacitor-twilio-video/)Join Twilio Video rooms from Capacitor with native audio, camera, and room lifecycle events Opens the plugin repository until a dedicated docs page is available. [Twilio Voice ](https://github.com/Cap-go/capacitor-twilio-voice/)Make and receive VoIP calls with Twilio Voice for in-app calling functionality Opens the plugin repository until a dedicated docs page is available. [Updater ](https://github.com/Cap-go/capacitor-updater/)Deploy live updates instantly to your users without app store review delays Opens the plugin repository until a dedicated docs page is available. [Uploader ](https://github.com/Cap-go/capacitor-uploader/)Upload large files reliably in background with progress tracking and retry support Opens the plugin repository until a dedicated docs page is available. [Usage Stats Manager ](https://github.com/Cap-go/capacitor-android-usagestatsmanager/)Access Android usage statistics to track app usage time and screen time analytics Opens the plugin repository until a dedicated docs page is available. [Video Player ](https://github.com/Cap-go/capacitor-video-player/)Native video playback with subtitles, fullscreen, and comprehensive controls Opens the plugin repository until a dedicated docs page is available. [Video Thumbnails ](https://github.com/Cap-go/capacitor-video-thumbnails/)Generate thumbnail images from local and remote video files at specific timestamps Opens the plugin repository until a dedicated docs page is available. [Volume Buttons ](https://github.com/Cap-go/capacitor-volume-buttons/)Capture hardware volume button presses for custom app controls and shortcuts Opens the plugin repository until a dedicated docs page is available. [Watch ](https://github.com/Cap-go/capacitor-watch/)Apple Watch communication with bidirectional messaging between iPhone and watchOS apps Opens the plugin repository until a dedicated docs page is available. [WebView Crash ](https://github.com/Cap-go/capacitor-webview-crash/)Detect recovered WebView crashes and tell the next JavaScript runtime what happened Opens the plugin repository until a dedicated docs page is available. [WebView Guardian ](https://github.com/Cap-go/capacitor-webview-guardian/)Detect when the WebView was killed in the background and relaunch it on foreground Opens the plugin repository until a dedicated docs page is available. [WebView Version Checker ](https://github.com/Cap-go/capacitor-webview-version-checker/)Capacitor plugin for checking Android WebView version freshness and guiding users to native update flows Opens the plugin repository until a dedicated docs page is available. [WeChat ](https://github.com/Cap-go/capacitor-wechat/)WeChat SDK for Capacitor - enables authentication, sharing, payments, and mini-programs Opens the plugin repository until a dedicated docs page is available. [Widget Kit ](https://github.com/Cap-go/capacitor-widget-kit/)Build WidgetKit and Live Activity surfaces from Capacitor with SVG frames, timers, action hotspots, or full-native widget state sync Opens the plugin repository until a dedicated docs page is available. [WiFi ](https://github.com/Cap-go/capacitor-wifi/)Manage WiFi connectivity for your Capacitor app Opens the plugin repository until a dedicated docs page is available. [YouTube Player ](https://github.com/Cap-go/capacitor-youtube-player/)Embed YouTube videos with full player API control and event handling Opens the plugin repository until a dedicated docs page is available. [Zebra DataWedge ](https://github.com/Cap-go/capacitor-zebra-datawedge/)Manage Zebra DataWedge profiles, notifications, queries, and scan triggers on Zebra Android devices Opens the plugin repository until a dedicated docs page is available. [Zip ](https://github.com/Cap-go/capacitor-zip/)A free Capacitor plugin for zipping and unzipping files on iOS, Android, and Web. Opens the plugin repository until a dedicated docs page is available. # @capgo/capacitor-accelerometer > Capacitor plugin contract for working with the device accelerometer. ## Overview [Section titled “Overview”](#overview) Capacitor plugin contract for working with the device accelerometer. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `getMeasurement` - Get the most recent accelerometer sample that was recorded by the native layer. * `isAvailable` - Check if the current device includes an accelerometer sensor. * `startMeasurementUpdates` - Begin streaming accelerometer updates to the JavaScript layer. * `stopMeasurementUpdates` - Stop streaming accelerometer updates started via . ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------------- | ------------------------------------------------------------------------------- | | `getMeasurement` | Get the most recent accelerometer sample that was recorded by the native layer. | | `isAvailable` | Check if the current device includes an accelerometer sensor. | | `startMeasurementUpdates` | Begin streaming accelerometer updates to the JavaScript layer. | | `stopMeasurementUpdates` | Stop streaming accelerometer updates started via . | | `checkPermissions` | Return the current permission state for accessing motion data. | | `requestPermissions` | Request permission to access motion data if supported by the platform. | | `addListener` | Listen for measurement updates. | | `removeAllListeners` | Remove all listeners that have been registered on the plugin. | | `getPluginVersion` | Get the native Capacitor plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-accelerometer](https://github.com/Cap-go/capacitor-accelerometer/). # Getting Started > Install @capgo/capacitor-accelerometer and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-accelerometer bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { CapacitorAccelerometer } from '@capgo/capacitor-accelerometer'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `getMeasurement` [Section titled “getMeasurement”](#getmeasurement) Get the most recent accelerometer sample that was recorded by the native layer. ```typescript import { CapacitorAccelerometer } from '@capgo/capacitor-accelerometer'; await CapacitorAccelerometer.getMeasurement(); ``` ### `isAvailable` [Section titled “isAvailable”](#isavailable) Check if the current device includes an accelerometer sensor. ```typescript import { CapacitorAccelerometer } from '@capgo/capacitor-accelerometer'; await CapacitorAccelerometer.isAvailable(); ``` ### `startMeasurementUpdates` [Section titled “startMeasurementUpdates”](#startmeasurementupdates) Begin streaming accelerometer updates to the JavaScript layer. Call with the `measurement` event to receive the updates. ```typescript import { CapacitorAccelerometer } from '@capgo/capacitor-accelerometer'; await CapacitorAccelerometer.startMeasurementUpdates(); ``` ### `stopMeasurementUpdates` [Section titled “stopMeasurementUpdates”](#stopmeasurementupdates) Stop streaming accelerometer updates started via . ```typescript import { CapacitorAccelerometer } from '@capgo/capacitor-accelerometer'; await CapacitorAccelerometer.stopMeasurementUpdates(); ``` ### `checkPermissions` [Section titled “checkPermissions”](#checkpermissions) Return the current permission state for accessing motion data. On platforms without explicit permissions this resolves to `granted`. ```typescript import { CapacitorAccelerometer } from '@capgo/capacitor-accelerometer'; await CapacitorAccelerometer.checkPermissions(); ``` ### `requestPermissions` [Section titled “requestPermissions”](#requestpermissions) Request permission to access motion data if supported by the platform. ```typescript import { CapacitorAccelerometer } from '@capgo/capacitor-accelerometer'; await CapacitorAccelerometer.requestPermissions(); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `GetMeasurementResult` [Section titled “GetMeasurementResult”](#getmeasurementresult) Alias for the most recent measurement. ```typescript export type GetMeasurementResult = Measurement; ``` ### `IsAvailableResult` [Section titled “IsAvailableResult”](#isavailableresult) Result returned by . ```typescript export interface IsAvailableResult { /** * Whether an accelerometer sensor is available on the device. * * @since 1.0.0 */ isAvailable: boolean; } ``` ### `PermissionStatus` [Section titled “PermissionStatus”](#permissionstatus) Permission information returned by and . ```typescript export interface PermissionStatus { /** * The permission state for accessing motion data on the current platform. * * @since 1.0.0 */ accelerometer: AccelerometerPermissionState; } ``` ### `MeasurementEvent` [Section titled “MeasurementEvent”](#measurementevent) Event payload emitted when is active. ```typescript export type MeasurementEvent = Measurement; ``` ### `Measurement` [Section titled “Measurement”](#measurement) The x, y and z axis acceleration values reported by the device motion sensors. ```typescript export interface Measurement { /** * The acceleration on the x-axis in G's. * * @since 1.0.0 */ x: number; /** * The acceleration on the y-axis in G's. * * @since 1.0.0 */ y: number; /** * The acceleration on the z-axis in G's. * * @since 1.0.0 */ z: number; } ``` ### `AccelerometerPermissionState` [Section titled “AccelerometerPermissionState”](#accelerometerpermissionstate) Permission state union including `limited` for platforms that can throttle motion access. ```typescript export type AccelerometerPermissionState = PermissionState | 'limited'; ``` ### `PermissionState` [Section titled “PermissionState”](#permissionstate) Platform permission states supported by Capacitor. ```typescript export type PermissionState = 'prompt' | 'prompt-with-rationale' | 'granted' | 'denied'; ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-admob > AdMob Plus Plugin interface for displaying Google AdMob ads in Capacitor apps. ## Overview [Section titled “Overview”](#overview) AdMob Plus Plugin interface for displaying Google AdMob ads in Capacitor apps. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `start` - Initialize and start the AdMob SDK. * `configure` - Configure AdMob settings. * `configRequest` - Configure ad request settings. * `adCreate` - Create a new ad instance. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------------------ | --------------------------------------------------------- | | `start` | Initialize and start the AdMob SDK. | | `configure` | Configure AdMob settings. | | `configRequest` | Configure ad request settings. | | `adCreate` | Create a new ad instance. | | `adIsLoaded` | Check if an ad is loaded and ready to be shown. | | `adLoad` | Load an ad. | | `adShow` | Show a loaded ad. | | `adHide` | Hide a currently displayed ad. | | `trackingAuthorizationStatus` | Get the current tracking authorization status (iOS only). | | `requestTrackingAuthorization` | Request tracking authorization from the user (iOS only). | | `addListener` | Add a listener for ad events. | | `getPluginVersion` | Get the native Capacitor plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-admob](https://github.com/Cap-go/capacitor-admob/). # Getting Started > Install @capgo/capacitor-admob and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-admob bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { AdMob } from '@capgo/capacitor-admob'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `start` [Section titled “start”](#start) Initialize and start the AdMob SDK. ```typescript import { AdMob } from '@capgo/capacitor-admob'; await AdMob.start(); ``` ### `configure` [Section titled “configure”](#configure) Configure AdMob settings. ```typescript import { AdMob } from '@capgo/capacitor-admob'; await AdMob.configure({ appMuted: false, appVolume: 0.5 }); ``` ### `configRequest` [Section titled “configRequest”](#configrequest) Configure ad request settings. ```typescript import { AdMob } from '@capgo/capacitor-admob'; await AdMob.configRequest({ maxAdContentRating: MaxAdContentRating.PG, tagForChildDirectedTreatment: true, testDeviceIds: ['test-device-id'] }); ``` ### `adCreate` [Section titled “adCreate”](#adcreate) Create a new ad instance. ```typescript import { AdMob } from '@capgo/capacitor-admob'; await AdMob.adCreate({ adUnitId: 'ca-app-pub-3940256099942544/1033173712' }); ``` ### `adIsLoaded` [Section titled “adIsLoaded”](#adisloaded) Check if an ad is loaded and ready to be shown. ```typescript import { AdMob } from '@capgo/capacitor-admob'; const isLoaded = await AdMob.adIsLoaded({ id: 1 }); if (isLoaded) { await AdMob.adShow({ id: 1 }); } ``` ### `adLoad` [Section titled “adLoad”](#adload) Load an ad. ```typescript import { AdMob } from '@capgo/capacitor-admob'; await AdMob.adLoad({ id: 1 }); ``` ### `adShow` [Section titled “adShow”](#adshow) Show a loaded ad. ```typescript import { AdMob } from '@capgo/capacitor-admob'; await AdMob.adShow({ id: 1 }); ``` ### `adHide` [Section titled “adHide”](#adhide) Hide a currently displayed ad. ```typescript import { AdMob } from '@capgo/capacitor-admob'; await AdMob.adHide({ id: 1 }); ``` ### `trackingAuthorizationStatus` [Section titled “trackingAuthorizationStatus”](#trackingauthorizationstatus) Get the current tracking authorization status (iOS only). ```typescript import { AdMob } from '@capgo/capacitor-admob'; const { status } = await AdMob.trackingAuthorizationStatus(); if (status === TrackingAuthorizationStatus.notDetermined) { await AdMob.requestTrackingAuthorization(); } ``` ### `requestTrackingAuthorization` [Section titled “requestTrackingAuthorization”](#requesttrackingauthorization) Request tracking authorization from the user (iOS only). ```typescript import { AdMob } from '@capgo/capacitor-admob'; const { status } = await AdMob.requestTrackingAuthorization(); console.log('User tracking status:', status); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `AdMobConfig` [Section titled “AdMobConfig”](#admobconfig) Configuration options for AdMob. ```typescript export type AdMobConfig = { /** Whether the app should be muted */ appMuted?: boolean; /** The app volume (0.0 to 1.0) */ appVolume?: number; }; ``` ### `RequestConfig` [Section titled “RequestConfig”](#requestconfig) Configuration for ad requests. ```typescript export type RequestConfig = { /** Maximum ad content rating */ maxAdContentRating?: MaxAdContentRating; /** Whether to use the same app key */ sameAppKey?: boolean; /** Tag for child-directed treatment (true, false, or null for unspecified) */ tagForChildDirectedTreatment?: boolean | null; /** Tag for under age of consent (true, false, or null for unspecified) */ tagForUnderAgeOfConsent?: boolean | null; /** Array of test device IDs */ testDeviceIds?: string[]; }; ``` ### `MobileAdOptions` [Section titled “MobileAdOptions”](#mobileadoptions) Base options for mobile ads. ```typescript export type MobileAdOptions = { /** The ad unit ID from AdMob */ adUnitId: string; }; ``` ### `TrackingAuthorizationStatus` [Section titled “TrackingAuthorizationStatus”](#trackingauthorizationstatus-1) Tracking authorization status for iOS App Tracking Transparency. ```typescript export enum TrackingAuthorizationStatus { /** User has not yet received an authorization request */ notDetermined = 0, /** User restricted, device is unable to provide authorization */ restricted = 1, /** User denied authorization */ denied = 2, /** User authorized access */ authorized = 3, } ``` ### `MaxAdContentRating` [Section titled “MaxAdContentRating”](#maxadcontentrating) Maximum ad content rating enum used to restrict ads based on content rating. ```typescript export enum MaxAdContentRating { /** General Audiences */ G = 'G', /** Mature Audiences */ MA = 'MA', /** Parental Guidance */ PG = 'PG', /** Teen */ T = 'T', /** Unspecified rating */ UNSPECIFIED = '', } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-age-range > Cross-platform age range detection plugin. ## Overview [Section titled “Overview”](#overview) Cross-platform age range detection plugin. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `requestAgeRange` - Request the user’s age range. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------ | ---------------------------------------- | | `requestAgeRange` | Request the user’s age range. | | `getPluginVersion` | Get the native Capacitor plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-age-range](https://github.com/Cap-go/capacitor-age-range/). # Getting Started > Install @capgo/capacitor-age-range and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-age-range bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { AgeRange } from '@capgo/capacitor-age-range'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `requestAgeRange` [Section titled “requestAgeRange”](#requestagerange) Request the user’s age range. On Android: queries Google Play Age Signals API (no user prompt). On iOS: presents the system DeclaredAgeRange dialog (requires iOS 26.2+). ```typescript import { AgeRange } from '@capgo/capacitor-age-range'; const result = await AgeRange.requestAgeRange({ ageGates: [13, 16, 18] }); if (result.status === 'SHARING') { console.log('Age range:', result.ageLower, '-', result.ageUpper); } ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `RequestAgeRangeOptions` [Section titled “RequestAgeRangeOptions”](#requestagerangeoptions) Options for the age range request. ```typescript export interface RequestAgeRangeOptions { /** * Age thresholds for the request. * * On iOS: these are passed to `requestAgeRange(ageGates:)` as the * age boundaries presented in the system dialog. Common values: [13, 16, 18]. * * On Android: this parameter is ignored (Play Age Signals returns * predefined ranges: 0-12, 13-15, 16-17, 18+). * * @default [13, 16, 18] * @since 8.0.0 */ ageGates?: number[]; } ``` ### `AgeRangeResult` [Section titled “AgeRangeResult”](#agerangeresult) Result of the age range request. ```typescript export interface AgeRangeResult { /** * The outcome status of the age range request. * * @since 8.0.0 */ status: AgeRangeStatus; /** * Inclusive lower bound of the user's age range. * * Present when age data is available. * * @since 8.0.0 */ ageLower?: number; /** * Inclusive upper bound of the user's age range. * * May be absent if the user is in the highest age bracket (e.g. 18+). * * @since 8.0.0 */ ageUpper?: number; /** * How the age was declared/determined. * * On iOS: 'SELF_DECLARED' or 'GUARDIAN_DECLARED'. * On Android: 'SUPERVISED' (guardian-managed) or 'VERIFIED' (Google-verified 18+). * * @since 8.0.0 */ declarationSource?: DeclarationSource; /** * Android-only. The user's Google Play verification status. * * @since 8.0.0 */ androidUserStatus?: AndroidUserStatus; /** * Android-only. Effective date for the most recent guardian-approved change. * * @since 8.0.0 */ mostRecentApprovalDate?: string; /** * Android-only. Install identifier for supervised installs in Google Play. * * @since 8.0.0 */ installId?: string; } ``` ### `AgeRangeStatus` [Section titled “AgeRangeStatus”](#agerangestatus) Top-level status of the age range request. ```typescript export type AgeRangeStatus = /** * The user shared their age range (iOS) or age signals are available (Android). */ | 'SHARING' /** * The user declined to share their age range. */ | 'DECLINED_SHARING' /** * The age range API is not available on this device/OS version. */ | 'NOT_AVAILABLE' /** * An error occurred while requesting the age range. */ | 'ERROR'; ``` ### `DeclarationSource` [Section titled “DeclarationSource”](#declarationsource) How the age range was declared or determined. ```typescript export type DeclarationSource = /** The user self-declared their age (iOS). */ | 'SELF_DECLARED' /** A guardian declared the user's age (iOS Family Sharing or Android supervised). */ | 'GUARDIAN_DECLARED' /** Google has verified the user is 18+ (Android only). */ | 'VERIFIED' /** Source is unknown or not provided by the platform. */ | 'UNKNOWN'; ``` ### `AndroidUserStatus` [Section titled “AndroidUserStatus”](#androiduserstatus) Android-specific Google Play user status values. ```typescript export type AndroidUserStatus = | 'VERIFIED' | 'SUPERVISED' | 'SUPERVISED_APPROVAL_PENDING' | 'SUPERVISED_APPROVAL_DENIED' | 'UNKNOWN' | 'EMPTY'; ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-android-age-signals > Capacitor interface for retrieving Play Age Signals. ## Overview [Section titled “Overview”](#overview) Capacitor interface for retrieving Play Age Signals. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `checkAgeSignals` - Request the current Play Age Signals for the active user. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------ | --------------------------------------------------------- | | `checkAgeSignals` | Request the current Play Age Signals for the active user. | | `getPluginVersion` | Get the native Capacitor plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-android-age-signals](https://github.com/Cap-go/capacitor-android-age-signals/). # Getting Started > Install @capgo/capacitor-android-age-signals and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-android-age-signals bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { AgeSignals } from '@capgo/capacitor-android-age-signals'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `checkAgeSignals` [Section titled “checkAgeSignals”](#checkagesignals) Request the current Play Age Signals for the active user. Only available on Android devices with Google Play installed. ```typescript import { AgeSignals } from '@capgo/capacitor-android-age-signals'; await AgeSignals.checkAgeSignals(); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `CheckAgeSignalsResult` [Section titled “CheckAgeSignalsResult”](#checkagesignalsresult) Structured result returned by . ```typescript export interface CheckAgeSignalsResult { /** * The user's verification status as reported by Google Play. * * @since 0.0.1 */ userStatus: UserStatus; /** * Inclusive lower bound of the supervised user's age range. * * Present only when `userStatus` is `SUPERVISED`, `SUPERVISED_APPROVAL_PENDING`, or `SUPERVISED_APPROVAL_DENIED`. * * @since 0.0.1 * @example 13 */ ageLower?: number; /** * Inclusive upper bound of the supervised user's age range. * * Present only when `userStatus` is `SUPERVISED`, `SUPERVISED_APPROVAL_PENDING`, or `SUPERVISED_APPROVAL_DENIED` * and the user's age is reported as less than 18. * * @since 0.0.1 * @example 15 */ ageUpper?: number; /** * Effective date for the most recent significant change that received guardian approval. * * Present only when `userStatus` is `SUPERVISED_APPROVAL_PENDING` or `SUPERVISED_APPROVAL_DENIED`. * * @since 0.0.1 * @example "2024-01-15" */ mostRecentApprovalDate?: string; /** * Identifier assigned to supervised installs in Google Play for revocation notifications. * * Present only when `userStatus` is `SUPERVISED`, `SUPERVISED_APPROVAL_PENDING`, or `SUPERVISED_APPROVAL_DENIED`. * * @since 0.0.1 * @example "abc123xyz" */ installId?: string; } ``` ### `UserStatus` [Section titled “UserStatus”](#userstatus) Status values reported by Google Play Age Signals. ```typescript export enum UserStatus { /** * The user is over 18 and their age has been verified by Google. * * @since 0.0.1 */ Verified = 'VERIFIED', /** * The user has a supervised Google Account managed by a guardian. * * Use `ageLower` and `ageUpper` to determine the user's age range. * * @since 0.0.1 */ Supervised = 'SUPERVISED', /** * The supervised user has pending significant changes awaiting guardian approval. * * Use `ageLower` and `ageUpper` to determine the user's age range and `mostRecentApprovalDate` * to identify the most recent approved change. * * @since 0.0.1 */ SupervisedApprovalPending = 'SUPERVISED_APPROVAL_PENDING', /** * The supervised user's guardian denied one or more significant changes. * * Use `ageLower` and `ageUpper` to determine the user's age range and `mostRecentApprovalDate` * to identify the last approved change. * * @since 0.0.1 */ SupervisedApprovalDenied = 'SUPERVISED_APPROVAL_DENIED', /** * The user is not verified or supervised in supported regions. * * You should prompt the user to resolve their status in the Play Store. * * @since 0.0.1 */ Unknown = 'UNKNOWN', /** * All other users return this value. * * @since 0.0.1 */ Empty = 'EMPTY', } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-alarm > Capacitor Alarm Plugin interface for managing native OS alarms. ## Overview [Section titled “Overview”](#overview) Capacitor Alarm Plugin interface for managing native OS alarms. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `createAlarm` - Create a native OS alarm using the platform clock app. On Android this uses the Alarm Clock intent; on iOS this uses AlarmKit if available (iOS 16+). * `openAlarms` - Open the platform’s native alarm list UI, if available. * `getOSInfo` - Get information about the OS and capabilities. * `requestPermissions` - Request relevant permissions for alarm usage on the platform. On Android, may route to settings for exact alarms. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `createAlarm` | Create a native OS alarm using the platform clock app. On Android this uses the Alarm Clock intent; on iOS this uses AlarmKit if available (iOS 16+). | | `openAlarms` | Open the platform’s native alarm list UI, if available. | | `getOSInfo` | Get information about the OS and capabilities. | | `requestPermissions` | Request relevant permissions for alarm usage on the platform. On Android, may route to settings for exact alarms. | | `checkPermissions` | Check the current permission state for native alarm access without triggering UI. On iOS this reports AlarmKit readiness; on Android it reports capability details. | | `getPluginVersion` | Get the native Capacitor plugin version. | | `getAlarms` | Get a list of alarms scheduled by this app. On iOS 26+, returns alarms from AlarmKit. On Android, this is not supported as the system does not provide an API to query alarms. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-alarm](https://github.com/Cap-go/capacitor-alarm/). # Getting Started > Install @capgo/capacitor-alarm and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-alarm bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { CapgoAlarm } from '@capgo/capacitor-alarm'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `createAlarm` [Section titled “createAlarm”](#createalarm) Create a native OS alarm using the platform clock app. On Android this uses the Alarm Clock intent; on iOS this uses AlarmKit if available (iOS 16+). ```typescript import { CapgoAlarm } from '@capgo/capacitor-alarm'; const result = await CapgoAlarm.createAlarm({ hour: 7, minute: 30, label: 'Wake up', skipUi: false, vibrate: true }); console.log('Alarm created:', result.success); ``` ### `openAlarms` [Section titled “openAlarms”](#openalarms) Open the platform’s native alarm list UI, if available. ```typescript import { CapgoAlarm } from '@capgo/capacitor-alarm'; const result = await CapgoAlarm.openAlarms(); if (result.success) { console.log('Alarms UI opened'); } ``` ### `getOSInfo` [Section titled “getOSInfo”](#getosinfo) Get information about the OS and capabilities. ```typescript import { CapgoAlarm } from '@capgo/capacitor-alarm'; const info = await CapgoAlarm.getOSInfo(); console.log('Platform:', info.platform); console.log('Supports native alarms:', info.supportsNativeAlarms); if (info.platform === 'android') { console.log('Can schedule exact alarms:', info.canScheduleExactAlarms); } ``` ### `requestPermissions` [Section titled “requestPermissions”](#requestpermissions) Request relevant permissions for alarm usage on the platform. On Android, may route to settings for exact alarms. ```typescript import { CapgoAlarm } from '@capgo/capacitor-alarm'; const result = await CapgoAlarm.requestPermissions({ exactAlarm: true }); if (result.granted) { console.log('Permissions granted'); } else { console.log('Permissions denied'); } ``` ### `checkPermissions` [Section titled “checkPermissions”](#checkpermissions) Check the current permission state for native alarm access without triggering UI. On iOS this reports AlarmKit readiness; on Android it reports capability details. ```typescript import { CapgoAlarm } from '@capgo/capacitor-alarm'; const status = await CapgoAlarm.checkPermissions(); console.log('AlarmKit allowed?', status.details?.alarmKit); ``` ### `getAlarms` [Section titled “getAlarms”](#getalarms) Get a list of alarms scheduled by this app. On iOS 26+, returns alarms from AlarmKit. On Android, this is not supported as the system does not provide an API to query alarms. ```typescript import { CapgoAlarm } from '@capgo/capacitor-alarm'; const { alarms } = await CapgoAlarm.getAlarms(); console.log('Scheduled alarms:', alarms); alarms.forEach(alarm => { console.log(`Alarm ${alarm.id}: ${alarm.hour}:${alarm.minute} - ${alarm.label}`); }); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `NativeAlarmCreateOptions` [Section titled “NativeAlarmCreateOptions”](#nativealarmcreateoptions) Options for creating a native OS alarm via the platform clock app. ```typescript export interface NativeAlarmCreateOptions { /** Hour of day in 24h format (0-23) */ hour: number; /** Minute of hour (0-59) */ minute: number; /** Optional label for the alarm */ label?: string; /** Android only: attempt to skip UI if possible */ skipUi?: boolean; /** Android only: set alarm to vibrate */ vibrate?: boolean; } ``` ### `NativeActionResult` [Section titled “NativeActionResult”](#nativeactionresult) Result of a native action. ```typescript export interface NativeActionResult { /** Whether the action was successful */ success: boolean; /** Optional message with additional information */ message?: string; } ``` ### `OSInfo` [Section titled “OSInfo”](#osinfo) Returned info about current OS and capabilities. ```typescript export interface OSInfo { /** Platform identifier: 'ios' | 'android' | 'web' */ platform: string; /** OS version string */ version: string; /** Whether the platform exposes a native alarm app integration */ supportsNativeAlarms: boolean; /** Whether scheduling local notifications is supported */ supportsScheduledNotifications: boolean; /** Android only: whether exact alarms are allowed */ canScheduleExactAlarms?: boolean; } ``` ### `PermissionResult` [Section titled “PermissionResult”](#permissionresult) Result of a permissions request. ```typescript export interface PermissionResult { /** Overall grant for requested scope */ granted: boolean; /** Optional details by permission key */ details?: Record; /** Optional human readable diagnostic */ message?: string; } ``` ### `AlarmInfo` [Section titled “AlarmInfo”](#alarminfo) Information about a scheduled alarm. ```typescript export interface AlarmInfo { /** Unique identifier for the alarm */ id: string; /** Hour of day in 24h format (0-23) */ hour: number; /** Minute of hour (0-59) */ minute: number; /** Optional label for the alarm */ label?: string; /** Whether the alarm is enabled */ enabled?: boolean; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-android-inline-install > Android Inline Install Plugin for triggering Google Play in-app install flows. ## Overview [Section titled “Overview”](#overview) Android Inline Install Plugin for triggering Google Play in-app install flows. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `startInlineInstall` - Start an inline install flow using the Google Play overlay. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | -------------------- | ----------------------------------------------------------- | | `startInlineInstall` | Start an inline install flow using the Google Play overlay. | | `getPluginVersion` | Get the native Capacitor plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-android-inline-install](https://github.com/Cap-go/capacitor-android-inline-install/). # Getting Started > Install @capgo/capacitor-android-inline-install and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-android-inline-install bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { AndroidInlineInstall } from '@capgo/capacitor-android-inline-install'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `startInlineInstall` [Section titled “startInlineInstall”](#startinlineinstall) Start an inline install flow using the Google Play overlay. Note: Only eligible apps can use Inline Install. See: ```typescript import { AndroidInlineInstall } from '@capgo/capacitor-android-inline-install'; const result = await AndroidInlineInstall.startInlineInstall({ id: 'com.example.app', referrer: 'my-referrer', overlay: true, fallback: true }); if (result.started) { console.log('Install flow started'); if (result.fallbackUsed) { console.log('Using fallback Play Store link'); } } ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `StartInlineInstallOptions` [Section titled “StartInlineInstallOptions”](#startinlineinstalloptions) Options for starting an inline install flow. ```typescript export interface StartInlineInstallOptions { /** Package name of the app to be installed (target app). */ id: string; /** Referrer string to pass to Play. Optional but recommended. */ referrer?: string; /** * Package name of your app (caller). Defaults to the current app package * if omitted. */ callerId?: string; /** Optional Custom Store Listing ID. */ csl_id?: string; /** Whether to request the Play overlay. Defaults to true. */ overlay?: boolean; /** If true, falls back to full Play Store deep link when overlay unavailable. Defaults to true. */ fallback?: boolean; } ``` ### `StartInlineInstallResult` [Section titled “StartInlineInstallResult”](#startinlineinstallresult) Result of starting an inline install flow. ```typescript export interface StartInlineInstallResult { /** True when the inline install intent has been started. */ started: boolean; /** True if a fallback deep link was used instead of inline overlay. */ fallbackUsed?: boolean; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-android-kiosk > Capacitor Android Kiosk Plugin for controlling kiosk mode and launcher functionality. This plugin is Android-only. For iOS kiosk mode, use the device's Guided Access feature. ## Overview [Section titled “Overview”](#overview) Capacitor Android Kiosk Plugin for controlling kiosk mode and launcher functionality. This plugin is Android-only. For iOS kiosk mode, use the device’s Guided Access feature. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `isInKioskMode` - Checks if the app is currently running in kiosk mode. * `isSetAsLauncher` - Checks if the app is set as the device launcher (home app). * `enterKioskMode` - Enters kiosk mode, hiding system UI and blocking hardware buttons. Also starts a foreground keep-alive service so the app is less likely to be killed by the system. The app must be set as the device launcher for this to work effectively. * `exitKioskMode` - Exits kiosk mode, restoring normal system UI and hardware button functionality. Also stops the foreground keep-alive service started in enterKioskMode(). ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `isInKioskMode` | Checks if the app is currently running in kiosk mode. | | `isSetAsLauncher` | Checks if the app is set as the device launcher (home app). | | `enterKioskMode` | Enters kiosk mode, hiding system UI and blocking hardware buttons. Also starts a foreground keep-alive service so the app is less likely to be killed by the system. The app must be set as the device launcher for this to work effectively. | | `exitKioskMode` | Exits kiosk mode, restoring normal system UI and hardware button functionality. Also stops the foreground keep-alive service started in enterKioskMode(). | | `setAsLauncher` | Opens the device’s home screen settings to allow user to set this app as the launcher. This is required for full kiosk mode functionality. | | `setAllowedKeys` | Sets which hardware keys are allowed to function in kiosk mode. By default, all hardware keys are blocked in kiosk mode. | | `getPluginVersion` | Get the native Capacitor plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-android-kiosk](https://github.com/Cap-go/capacitor-android-kiosk/). # Getting Started > Install @capgo/capacitor-android-kiosk and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-android-kiosk bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { CapacitorAndroidKiosk } from '@capgo/capacitor-android-kiosk'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `isInKioskMode` [Section titled “isInKioskMode”](#isinkioskmode) Checks if the app is currently running in kiosk mode. ```typescript import { CapacitorAndroidKiosk } from '@capgo/capacitor-android-kiosk'; const { isInKioskMode } = await CapacitorAndroidKiosk.isInKioskMode(); console.log('Kiosk mode active:', isInKioskMode); ``` ### `isSetAsLauncher` [Section titled “isSetAsLauncher”](#issetaslauncher) Checks if the app is set as the device launcher (home app). ```typescript import { CapacitorAndroidKiosk } from '@capgo/capacitor-android-kiosk'; const { isLauncher } = await CapacitorAndroidKiosk.isSetAsLauncher(); console.log('Is launcher:', isLauncher); ``` ### `enterKioskMode` [Section titled “enterKioskMode”](#enterkioskmode) Enters kiosk mode, hiding system UI and blocking hardware buttons. Also starts a foreground keep-alive service so the app is less likely to be killed by the system. The app must be set as the device launcher for this to work effectively. ```typescript import { CapacitorAndroidKiosk } from '@capgo/capacitor-android-kiosk'; await CapacitorAndroidKiosk.enterKioskMode(); ``` ### `exitKioskMode` [Section titled “exitKioskMode”](#exitkioskmode) Exits kiosk mode, restoring normal system UI and hardware button functionality. Also stops the foreground keep-alive service started in enterKioskMode(). ```typescript import { CapacitorAndroidKiosk } from '@capgo/capacitor-android-kiosk'; await CapacitorAndroidKiosk.exitKioskMode(); console.log('Exited kiosk mode'); ``` ### `setAsLauncher` [Section titled “setAsLauncher”](#setaslauncher) Opens the device’s home screen settings to allow user to set this app as the launcher. This is required for full kiosk mode functionality. ```typescript import { CapacitorAndroidKiosk } from '@capgo/capacitor-android-kiosk'; await CapacitorAndroidKiosk.setAsLauncher(); // User will be prompted to select this app as the home app ``` ### `setAllowedKeys` [Section titled “setAllowedKeys”](#setallowedkeys) Sets which hardware keys are allowed to function in kiosk mode. By default, all hardware keys are blocked in kiosk mode. ```typescript import { CapacitorAndroidKiosk } from '@capgo/capacitor-android-kiosk'; // Allow volume keys only await CapacitorAndroidKiosk.setAllowedKeys({ volumeUp: true, volumeDown: true, back: false, home: false, recent: false }); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `EnterKioskModeOptions` [Section titled “EnterKioskModeOptions”](#enterkioskmodeoptions) Optional flags for `enterKioskMode`. ```typescript export interface EnterKioskModeOptions { /** * After reboot, start the app so you can call `enterKioskMode()` again. Best-effort only (OEM * behavior, force-stop). Omit to keep the saved value. Cleared when you call `exitKioskMode()`. */ restoreAfterReboot?: boolean; /** * Periodically tries to bring the app to the foreground. Skipped while the screen is off. Often * blocked from the background on some devices—being the default launcher, relaxing battery limits, * and allowing exact alarms (where required) improve odds. Omit to keep the saved value. */ relaunch?: boolean; /** Minutes between relaunch attempts when `relaunch` is on. Range 5–60; default 15. */ relaunchIntervalMinutes?: number; } ``` ### `AllowedKeysOptions` [Section titled “AllowedKeysOptions”](#allowedkeysoptions) Configuration options for allowed hardware keys in kiosk mode. ```typescript export interface AllowedKeysOptions { /** * Allow volume up button * @default false */ volumeUp?: boolean; /** * Allow volume down button * @default false */ volumeDown?: boolean; /** * Allow back button * @default false */ back?: boolean; /** * Allow home button * @default false */ home?: boolean; /** * Allow recent apps button * @default false */ recent?: boolean; /** * Allow power button * @default false */ power?: boolean; /** * Allow camera button (if present) * @default false */ camera?: boolean; /** * Allow menu button (if present) * @default false */ menu?: boolean; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-android-sms-retriever > Read one app-targeted verification SMS without SMS permissions and request SIM phone number hints on Android. ## Overview [Section titled “Overview”](#overview) `@capgo/capacitor-android-sms-retriever` wraps Google Play services SMS Retriever and Phone Number Hint APIs for Android-only Capacitor verification flows. The plugin lets your app listen for a single verification SMS addressed to your app without requesting SMS permissions. It can also show Android’s native Phone Number Hint UI so users can choose a SIM-based phone number without typing it manually. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `startWatch` - Start a five-minute SMS Retriever watch for one verification SMS. * `stopWatch` - Stop the active SMS Retriever watch. * `getHashString` - Read the 11-character app hash used in verification SMS messages. * `getPhoneNumber` - Open Android Phone Number Hint and return the selected phone number. * `smsReceived` - Listen for the retrieved verification SMS. * `smsRetrieverTimeout` - Listen for the five-minute timeout. * `smsRetrieverError` - Listen for runtime errors from Android or Google Play services. ## Platform Support [Section titled “Platform Support”](#platform-support) | Platform | Support | | -------- | ---------------- | | Android | Supported | | iOS | Unsupported stub | | Web | Unsupported stub | ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ----------------------------------------- | ------------------------------------------------------ | | `startWatch` | Start listening for one verification SMS. | | `stopWatch` | Stop the active watch. | | `getHashString` | Return the 11-character app hash. | | `getPhoneNumber` | Show Phone Number Hint and return the selected number. | | `addListener('smsReceived', ...)` | Receive the retrieved SMS payload. | | `addListener('smsRetrieverTimeout', ...)` | Handle timeout events. | | `addListener('smsRetrieverError', ...)` | Handle retriever errors. | | `getPluginVersion` | Return the native plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-android-sms-retriever](https://github.com/Cap-go/capacitor-android-sms-retriever/). # Getting Started > Install @capgo/capacitor-android-sms-retriever and use Android SMS Retriever in a Capacitor app. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-android-sms-retriever bunx cap sync android ``` ## Import [Section titled “Import”](#import) ```typescript import { AndroidSmsRetriever } from '@capgo/capacitor-android-sms-retriever'; ``` ## Android Requirements [Section titled “Android Requirements”](#android-requirements) SMS Retriever requires Google Play services on the Android device. The plugin does not request `READ_SMS` or `RECEIVE_SMS` permissions. Your verification SMS must include the app hash returned by `getHashString()`. Generate the hash for the signing key used to distribute the app. Debug, release, and Play App Signing builds can have different hashes. ## Listen For A Verification SMS [Section titled “Listen For A Verification SMS”](#listen-for-a-verification-sms) ```typescript import { AndroidSmsRetriever } from '@capgo/capacitor-android-sms-retriever'; const received = await AndroidSmsRetriever.addListener('smsReceived', ({ message }) => { const code = message.match(/\b\d{6}\b/)?.[0]; console.log('Verification code:', code); }); const timeout = await AndroidSmsRetriever.addListener('smsRetrieverTimeout', () => { console.log('SMS Retriever timed out'); }); const errors = await AndroidSmsRetriever.addListener('smsRetrieverError', ({ message }) => { console.error('SMS Retriever error:', message); }); await AndroidSmsRetriever.startWatch(); // Remove listeners when the verification flow is done. await received.remove(); await timeout.remove(); await errors.remove(); ``` ## Stop Watching [Section titled “Stop Watching”](#stop-watching) ```typescript await AndroidSmsRetriever.stopWatch(); ``` ## Get The App Hash [Section titled “Get The App Hash”](#get-the-app-hash) ```typescript const { hash } = await AndroidSmsRetriever.getHashString(); console.log(hash); ``` Use this hash at the end of the verification SMS sent by your backend. ## Request A Phone Number Hint [Section titled “Request A Phone Number Hint”](#request-a-phone-number-hint) ```typescript const { phoneNumber } = await AndroidSmsRetriever.getPhoneNumber(); console.log(phoneNumber); ``` Android shows the native Phone Number Hint UI and returns the phone number selected by the user. ## Example SMS [Section titled “Example SMS”](#example-sms) ```text <#> 123456 is your verification code. FA+9qCX9VSu ``` Replace the final line with the hash for your app signing key. # @capgo/capacitor-android-usagestatsmanager > Capacitor plugin for accessing Android UsageStatsManager API. ## Overview [Section titled “Overview”](#overview) Capacitor plugin for accessing Android UsageStatsManager API. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `queryAndAggregateUsageStats` - Queries and aggregates usage stats for the given time range. * `isUsageStatsPermissionGranted` - Checks if the usage stats permission is granted. * `openUsageStatsSettings` - Open the usage stats settings screen. This will open the usage stats settings screen, which allows the user to grant the usage stats permission. This will always open the settings screen, even if the permission is already granted. * `queryAllPackages` - Queries all installed packages on the device. Requires the QUERY\_ALL\_PACKAGES permission. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `queryAndAggregateUsageStats` | Queries and aggregates usage stats for the given time range. | | `isUsageStatsPermissionGranted` | Checks if the usage stats permission is granted. | | `openUsageStatsSettings` | Open the usage stats settings screen. This will open the usage stats settings screen, which allows the user to grant the usage stats permission. This will always open the settings screen, even if the permission is already granted. | | `queryAllPackages` | Queries all installed packages on the device. Requires the QUERY\_ALL\_PACKAGES permission. | | `getPluginVersion` | Get the native Capacitor plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-android-usagestatsmanager](https://github.com/Cap-go/capacitor-android-usagestatsmanager/). # Getting Started > Install @capgo/capacitor-android-usagestatsmanager and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-android-usagestatsmanager bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { CapacitorUsageStatsManager } from '@capgo/capacitor-android-usagestatsmanager'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `queryAndAggregateUsageStats` [Section titled “queryAndAggregateUsageStats”](#queryandaggregateusagestats) Queries and aggregates usage stats for the given time range. ```typescript import { CapacitorUsageStatsManager } from '@capgo/capacitor-android-usagestatsmanager'; const oneDayAgo = Date.now() - 24 * 60 * 60 * 1000; const now = Date.now(); const stats = await UsageStatsManager.queryAndAggregateUsageStats({ beginTime: oneDayAgo, endTime: now }); for (const [packageName, usageData] of Object.entries(stats)) { console.log(`${packageName}: ${usageData.totalTimeInForeground}ms`); } ``` ### `isUsageStatsPermissionGranted` [Section titled “isUsageStatsPermissionGranted”](#isusagestatspermissiongranted) Checks if the usage stats permission is granted. ```typescript import { CapacitorUsageStatsManager } from '@capgo/capacitor-android-usagestatsmanager'; const { granted } = await UsageStatsManager.isUsageStatsPermissionGranted(); if (!granted) { await UsageStatsManager.openUsageStatsSettings(); } ``` ### `openUsageStatsSettings` [Section titled “openUsageStatsSettings”](#openusagestatssettings) Open the usage stats settings screen. This will open the usage stats settings screen, which allows the user to grant the usage stats permission. This will always open the settings screen, even if the permission is already granted. ```typescript import { CapacitorUsageStatsManager } from '@capgo/capacitor-android-usagestatsmanager'; await UsageStatsManager.openUsageStatsSettings(); ``` ### `queryAllPackages` [Section titled “queryAllPackages”](#queryallpackages) Queries all installed packages on the device. Requires the QUERY\_ALL\_PACKAGES permission. ```typescript import { CapacitorUsageStatsManager } from '@capgo/capacitor-android-usagestatsmanager'; const { packages } = await UsageStatsManager.queryAllPackages(); packages.forEach(pkg => { console.log(`${pkg.appName} (${pkg.packageName}): v${pkg.versionName}`); }); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `UsageStatsOptions` [Section titled “UsageStatsOptions”](#usagestatsoptions) Options for querying usage statistics. ```typescript export interface UsageStatsOptions { /** * The inclusive beginning of the range of stats to include in the results. * Defined in terms of "Unix time" */ beginTime: number; /** * The exclusive end of the range of stats to include in the results. * Defined in terms of "Unix time" */ endTime: number; } ``` ### `UsageStats` [Section titled “UsageStats”](#usagestats) Usage statistics for an Android app. ```typescript export interface UsageStats { /** * The first timestamp of the usage stats. */ firstTimeStamp: number; /** * The last timestamp of the usage stats. */ lastTimeStamp: number; /** * Only available on Android Q (API level 29) and above. * Will be undefined on lower Android versions. */ lastTimeForegroundServiceUsed?: number; /** * The last time the app was used. */ lastTimeUsed: number; /** * Only available on Android Q (API level 29) and above. * Will be undefined on lower Android versions. */ lastTimeVisible?: number; /** * The name of the package. */ packageName: string; /** * Only available on Android Q (API level 29) and above. * Will be undefined on lower Android versions. */ totalForegroundServiceUsed?: number; /** * The total time the app was in the foreground. */ totalTimeInForeground: number; /** * Only available on Android Q (API level 29) and above. * Will be undefined on lower Android versions. */ totalTimeVisible?: number; } ``` ### `UsageStatsPermissionResult` [Section titled “UsageStatsPermissionResult”](#usagestatspermissionresult) Result of a usage stats permission check. ```typescript export interface UsageStatsPermissionResult { /** * Whether the usage stats permission is granted. */ granted: boolean; } ``` ### `PackageInfo` [Section titled “PackageInfo”](#packageinfo) Represents basic information about an installed package. ```typescript export interface PackageInfo { /** Package name */ packageName: string; /** App display name */ appName: string; /** Version name string */ versionName: string; /** Version code number */ versionCode: number; /** First install time in milliseconds since epoch */ firstInstallTime: number; /** Last update time in milliseconds since epoch */ lastUpdateTime: number; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-app-attest > Unified cross-platform attestation plugin for Capacitor. ## Overview [Section titled “Overview”](#overview) Unified cross-platform attestation plugin for Capacitor. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `isSupported` - Checks whether native attestation is available on this device. * `prepare` - Prepares attestation state and returns the key handle used for later calls. * `createAttestation` - Creates a registration attestation token bound to a backend-issued challenge. * `createAssertion` - Creates a request assertion token bound to a request payload. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------- | ----------------------------------------------------------------------------- | | `isSupported` | Checks whether native attestation is available on this device. | | `prepare` | Prepares attestation state and returns the key handle used for later calls. | | `createAttestation` | Creates a registration attestation token bound to a backend-issued challenge. | | `createAssertion` | Creates a request assertion token bound to a request payload. | | `storeKeyId` | Stores/prepares a key identifier for reuse. | | `getStoredKeyId` | Returns the currently stored/prepared key identifier. | | `clearStoredKeyId` | Clears stored/prepared key identifiers. | | `generateKey` | Legacy alias for `prepare()`. | | `attestKey` | Legacy alias for `createAttestation()`. | | `generateAssertion` | Legacy alias for `createAssertion()`. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-app-attest](https://github.com/Cap-go/capacitor-app-attest/). # Android Setup & Backend Verification > Configure Google Play Integrity Standard API on Android and verify integrity tokens on your backend. ## Android native system used [Section titled “Android native system used”](#android-native-system-used) On Android, this plugin uses **Google Play Integrity Standard API**: * `prepareIntegrityToken` during `prepare()` * `requestStandardIntegrityToken` for `createAttestation()` and `createAssertion()` ## Requirements [Section titled “Requirements”](#requirements) * Android app distributed through Google Play ecosystem * Google Play services available on device * Play Integrity API enabled for your app * Google Cloud project number configured ## Google setup [Section titled “Google setup”](#google-setup) 1. Enable **Play Integrity API** in your Google Cloud project. 2. Open Play Console and configure Play Integrity access for your app. 3. Provide `cloudProjectNumber` to the plugin. ## Capacitor config [Section titled “Capacitor config”](#capacitor-config) capacitor.config.ts ```ts plugins: { AppAttest: { cloudProjectNumber: '123456789012', }, } ``` You can also pass `cloudProjectNumber` per call in method options. ## Client flow [Section titled “Client flow”](#client-flow) ```typescript import { AppAttest } from '@capgo/capacitor-app-attest'; const { keyId } = await AppAttest.prepare({ cloudProjectNumber: '123456789012', }); const attestation = await AppAttest.createAttestation({ keyId, challenge: 'backend-registration-challenge', }); const assertion = await AppAttest.createAssertion({ keyId, payload: 'backend-request-payload', }); ``` `token` is a Play Integrity token and must be decoded server-side. ## Backend workflow (Android) [Section titled “Backend workflow (Android)”](#backend-workflow-android) ### Registration (`createAttestation`) [Section titled “Registration (createAttestation)”](#registration-createattestation) 1. Backend creates one-time `challenge`. 2. App calls `createAttestation({ keyId, challenge })`. 3. Backend calls Google `decodeIntegrityToken` API. 4. Backend verifies at minimum: * `requestDetails.requestHash === base64url(SHA256(challenge))` * `appIntegrity.packageName` equals your Android application id * `appIntegrity.certificateSha256Digest` contains your release signing cert digest * integrity verdicts match your security policy ### Request protection (`createAssertion`) [Section titled “Request protection (createAssertion)”](#request-protection-createassertion) 1. Backend creates one-time `payload`. 2. App calls `createAssertion({ keyId, payload })`. 3. Backend decodes token and checks `requestHash === base64url(SHA256(payload))`. 4. Enforce replay prevention (single-use + TTL) and integrity verdict policy. ## Android schema [Section titled “Android schema”](#android-schema) ```mermaid sequenceDiagram participant App as Android App participant Plugin as AppAttest plugin participant PlaySDK as Play Integrity SDK participant BE as Backend participant Google as decodeIntegrityToken API App->>Plugin: prepare(cloudProjectNumber) Plugin->>PlaySDK: prepareIntegrityToken() PlaySDK-->>Plugin: provider handle (keyId) BE->>App: one-time challenge App->>Plugin: createAttestation(keyId, challenge) Plugin->>PlaySDK: requestStandardIntegrityToken(requestHash) PlaySDK-->>Plugin: integrity token Plugin-->>App: token + platform + format + keyId App->>BE: token + challenge + keyId BE->>Google: decodeIntegrityToken(token) Google-->>BE: decoded payload BE->>BE: verify requestHash + app identity + verdicts BE->>App: one-time payload App->>Plugin: createAssertion(keyId, payload) Plugin->>PlaySDK: requestStandardIntegrityToken(requestHash) PlaySDK-->>Plugin: integrity token App->>BE: token + payload + keyId BE->>Google: decodeIntegrityToken(token) Google-->>BE: decoded payload BE->>BE: verify requestHash + replay policy ``` ## Minimal backend payload contract [Section titled “Minimal backend payload contract”](#minimal-backend-payload-contract) Registration: ```json { "platform": "android", "format": "google-play-integrity-standard", "keyId": "string", "challenge": "string", "token": "string" } ``` Assertion: ```json { "platform": "android", "format": "google-play-integrity-standard", "keyId": "string", "payload": "string", "token": "string" } ``` # Getting Started > Learn how to install and use App Attest with a unified API for iOS and Android attestation. 1. **Install the package** ```sh bun add @capgo/capacitor-app-attest ``` 2. **Sync native projects** ```sh bunx cap sync ``` 3. **Configure platform requirements** * Complete [iOS setup](/docs/plugins/app-attest/ios/) for App Attest capability and backend verification flow. * Complete [Android setup](/docs/plugins/app-attest/android/) for Play Integrity Standard and backend verification flow. ## Why use this plugin [Section titled “Why use this plugin”](#why-use-this-plugin) This plugin provides one cross-platform API while keeping native platform security: * iOS: Apple App Attest (`DeviceCheck`) * Android: Google Play Integrity Standard API * No custom client-side crypto scheme * Normalized outputs for backend checks ## Usage [Section titled “Usage”](#usage) ```typescript import { AppAttest } from '@capgo/capacitor-app-attest'; const support = await AppAttest.isSupported(); if (!support.isSupported) { throw new Error(`Attestation not supported on ${support.platform}`); } const prepared = await AppAttest.prepare(); const registration = await AppAttest.createAttestation({ keyId: prepared.keyId, challenge: 'backend-one-time-registration-challenge', }); const assertion = await AppAttest.createAssertion({ keyId: prepared.keyId, payload: 'backend-one-time-request-payload', }); console.log(registration.platform, registration.format, registration.token); console.log(assertion.platform, assertion.format, assertion.token); ``` ## Unified response shape [Section titled “Unified response shape”](#unified-response-shape) `createAttestation()` and `createAssertion()` return the same key fields on iOS and Android: | Field | Type | Description | | ---------- | ----------------------------- | ------------------------------------------------------ | | `platform` | `'ios' \| 'android' \| 'web'` | Native platform that produced the token | | `format` | `AttestationFormat` | `apple-app-attest` or `google-play-integrity-standard` | | `keyId` | `string` | Key/provider handle used for attestation | | `token` | `string` | Token to verify on your backend | ## Backend requirement [Section titled “Backend requirement”](#backend-requirement) Attestation is only useful when verified server-side. * Never trust client-only success. * Require one-time challenge/payload values from your backend. * Verify `token`, app identity, and replay protections in backend logic. Use the platform-specific backend guides: * [iOS setup and backend verification](/docs/plugins/app-attest/ios/) * [Android setup and backend verification](/docs/plugins/app-attest/android/) # iOS Setup & Backend Verification > Configure Apple App Attest on iOS and verify attestation/assertion payloads on your backend. ## iOS native system used [Section titled “iOS native system used”](#ios-native-system-used) On iOS, this plugin uses **Apple App Attest** from the `DeviceCheck` framework. ## Requirements [Section titled “Requirements”](#requirements) * iOS 14+ * Physical device recommended for real validation flows * Xcode target with App Attest capability enabled ## Xcode setup [Section titled “Xcode setup”](#xcode-setup) 1. Open your iOS app target in Xcode. 2. Go to **Signing & Capabilities**. 3. Click **+ Capability** and add **App Attest**. No custom iOS permissions are required in `Info.plist` for App Attest itself. ## Client flow [Section titled “Client flow”](#client-flow) ```typescript import { AppAttest } from '@capgo/capacitor-app-attest'; const { keyId } = await AppAttest.prepare(); const attestation = await AppAttest.createAttestation({ keyId, challenge: 'backend-registration-challenge', }); const assertion = await AppAttest.createAssertion({ keyId, payload: 'backend-request-payload', }); ``` Send `attestation.token` and `assertion.token` to your backend. Do not validate them in the app. ## Backend workflow (iOS) [Section titled “Backend workflow (iOS)”](#backend-workflow-ios) ### Registration (`createAttestation`) [Section titled “Registration (createAttestation)”](#registration-createattestation) 1. Backend creates one-time `challenge`. 2. App calls `createAttestation({ keyId, challenge })`. 3. Backend verifies App Attest attestation: * certificate chain is valid and anchored to Apple App Attest * app identity matches your app (`bundleId`, team) * `clientDataHash` matches `SHA256(challenge)` 4. Store device key state (`keyId`, public key, and verifier metadata). ### Request protection (`createAssertion`) [Section titled “Request protection (createAssertion)”](#request-protection-createassertion) 1. Backend creates one-time `payload` (or canonical request hash input). 2. App calls `createAssertion({ keyId, payload })`. 3. Backend verifies assertion signature with previously stored key material. 4. Enforce replay protection and nonce TTL checks. ## iOS schema [Section titled “iOS schema”](#ios-schema) ```mermaid sequenceDiagram participant App as iOS App participant Plugin as AppAttest plugin participant Apple as Apple App Attest participant BE as Backend BE->>App: one-time challenge App->>Plugin: prepare() Plugin->>Apple: generateKey() Apple-->>Plugin: keyId App->>Plugin: createAttestation(keyId, challenge) Plugin->>Apple: attestKey(keyId, SHA256(challenge)) Apple-->>Plugin: attestation token Plugin-->>App: token + platform + format + keyId App->>BE: token + challenge + keyId BE->>BE: verify Apple attestation rules BE->>App: one-time payload App->>Plugin: createAssertion(keyId, payload) Plugin->>Apple: generateAssertion(keyId, SHA256(payload)) Apple-->>Plugin: assertion token Plugin-->>App: token + platform + format + keyId App->>BE: token + payload + keyId BE->>BE: verify signature + replay policy ``` ## Minimal backend payload contract [Section titled “Minimal backend payload contract”](#minimal-backend-payload-contract) Registration: ```json { "platform": "ios", "format": "apple-app-attest", "keyId": "string", "challenge": "string", "token": "string" } ``` Assertion: ```json { "platform": "ios", "format": "apple-app-attest", "keyId": "string", "payload": "string", "token": "string" } ``` # @capgo/capacitor-app-tracking-transparency > Capacitor App Tracking Transparency Plugin. ## Overview [Section titled “Overview”](#overview) Capacitor App Tracking Transparency Plugin. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `getStatus` - Gets the current tracking authorization status without prompting the user. * `requestPermission` - Requests user authorization to access app-related data for tracking. Displays the native iOS tracking permission dialog. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------- | ------------------------------------------------------------------------------------------------------------------------ | | `getStatus` | Gets the current tracking authorization status without prompting the user. | | `requestPermission` | Requests user authorization to access app-related data for tracking. Displays the native iOS tracking permission dialog. | | `getPluginVersion` | Get the native Capacitor plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-app-tracking-transparency](https://github.com/Cap-go/capacitor-app-tracking-transparency/). # Getting Started > Install @capgo/capacitor-app-tracking-transparency and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-app-tracking-transparency bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { AppTrackingTransparency } from '@capgo/capacitor-app-tracking-transparency'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `getStatus` [Section titled “getStatus”](#getstatus) Gets the current tracking authorization status without prompting the user. ```typescript import { AppTrackingTransparency } from '@capgo/capacitor-app-tracking-transparency'; const { status } = await AppTrackingTransparency.getStatus(); if (status === 'authorized') { console.log('Tracking is authorized'); } ``` ### `requestPermission` [Section titled “requestPermission”](#requestpermission) Requests user authorization to access app-related data for tracking. Displays the native iOS tracking permission dialog. Note: This method will only show the dialog once. Subsequent calls will return the stored authorization status without showing the dialog. ```typescript import { AppTrackingTransparency } from '@capgo/capacitor-app-tracking-transparency'; const { status } = await AppTrackingTransparency.requestPermission(); switch (status) { case 'authorized': console.log('User authorized tracking'); break; case 'denied': console.log('User denied tracking'); break; case 'restricted': console.log('Tracking is restricted'); break; case 'notDetermined': console.log('Status not determined'); break; } ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `AppTrackingStatusResponse` [Section titled “AppTrackingStatusResponse”](#apptrackingstatusresponse) Response object containing the tracking authorization status. ```typescript export interface AppTrackingStatusResponse { /** * The current tracking authorization status. * * @since 1.0.0 */ status: AppTrackingStatus; } ``` ### `AppTrackingStatus` [Section titled “AppTrackingStatus”](#apptrackingstatus) Possible values for the tracking authorization status. ```typescript export type AppTrackingStatus = 'authorized' | 'denied' | 'notDetermined' | 'restricted'; ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-appinsights > A wrapper around the https://github.com/apptopia/appinsights SDK. ## Overview [Section titled “Overview”](#overview) A wrapper around the SDK. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `init` - Initialize the AppInsights SDK. * `setUserId` - Set or update the user ID after initialization. * `getState` - Get the current state of the SDK. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------ | ----------------------------------------------- | | `init` | Initialize the AppInsights SDK. | | `setUserId` | Set or update the user ID after initialization. | | `getState` | Get the current state of the SDK. | | `getPluginVersion` | Get the native Capacitor plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-appinsights](https://github.com/Cap-go/capacitor-appinsights/). # Getting Started > Install @capgo/capacitor-appinsights and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-appinsights bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { CapacitorAppInsights } from '@capgo/capacitor-appinsights'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `init` [Section titled “init”](#init) Initialize the AppInsights SDK ```typescript import { CapacitorAppInsights } from '@capgo/capacitor-appinsights'; await CapacitorAppInsights.init({} as { partnerId: string; // Provided by our business unit partnerKey: string; // Provided by our business unit }); ``` ### `setUserId` [Section titled “setUserId”](#setuserid) Set or update the user ID after initialization ```typescript import { CapacitorAppInsights } from '@capgo/capacitor-appinsights'; await CapacitorAppInsights.setUserId({} as { userId: string }); ``` ### `getState` [Section titled “getState”](#getstate) Get the current state of the SDK ```typescript import { CapacitorAppInsights } from '@capgo/capacitor-appinsights'; await CapacitorAppInsights.getState(); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `PanelSDKState` [Section titled “PanelSDKState”](#panelsdkstate) ```typescript export interface PanelSDKState { initCompleted: boolean; // SDK initialization status jobScheduled: boolean; // Background job scheduling status permissionAcquired: boolean; // Required permissions status } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-appsflyer > Capacitor plugin for AppsFlyer attribution, analytics, and deep links. ## Overview [Section titled “Overview”](#overview) Capacitor plugin for AppsFlyer attribution, analytics, and deep links. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `initSDK` - Use this method to initialize and start AppsFlyer SDK. This API should be called as soon as the app launched. * `startSDK` - Use this method to start AppsFlyer SDK, only on manual start mode. * `logEvent` - Log an in-app event. * `setCustomerUserId` - Setting your own customer ID enables you to cross-reference your own unique ID with AppsFlyer’s unique ID and other devices’ IDs. This ID is available in raw-data reports and in the Postback APIs for cross-referencing with your internal IDs. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ---------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `addListener('conversion_callback', listener)` | Listen for conversion callbacks, including `onConversionDataSuccess` and `onConversionDataFail`, with `OnConversionDataResult` payloads. | | `addListener('oaoa_callback', listener)` | Listen for app-open attribution callbacks, including `onAppOpenAttribution` and `onAttributionFailure`, with `OnAppOpenAttribution` payloads. | | `addListener('udl_callback', listener)` | Listen for unified deep link callbacks with `OnDeepLink` payloads. | | `initSDK` | Use this method to initialize and start AppsFlyer SDK. This API should be called as soon as the app launched. | | `startSDK` | Use this method to start AppsFlyer SDK, only on manual start mode. | | `logEvent` | Log an in-app event. | | `setCustomerUserId` | Setting your own customer ID enables you to cross-reference your own unique ID with AppsFlyer’s unique ID and other devices’ IDs. This ID is available in raw-data reports and in the Postback APIs for cross-referencing with your internal IDs. | | `setCurrencyCode` | Sets the currency used for in-app purchases. Provide a three-character ISO 4217 code. | | `updateServerUninstallToken` | Pass GCM/FCM tokens on Android or APNs tokens on iOS when another plugin collected them. Use this to forward uninstall measurement tokens to AppsFlyer. | | `setAppInviteOneLink` | Sets the OneLink ID used as the base link for invite attribution. | | `setOneLinkCustomDomain` | Registers branded OneLink domains so AppsFlyer can resolve attribution parameters hidden in short links. | | `appendParametersToDeepLinkingURL` | Enables attribution for App Links deep links without OneLink. Call this method before `startSDK()`. Include at least `pid` and `is_retargeting=true` in the parameters map. | | `setResolveDeepLinkURLs` | Use this when an AppsFlyer OneLink is wrapped inside another Universal Link. It lets the SDK resolve the wrapped URL so deep linking still works correctly. | | `addPushNotificationDeepLinkPath` | Configures how the SDK extracts deep link values from push notification payloads. | | `setSharingFilter` | Stops events from propagating to the specified AppsFlyer partners. | | `setSharingFilterForAllPartners` | Stops events from propagating to all AppsFlyer partners. Overwrites setSharingFilter. | | `setSharingFilterForPartners` | Stops events from propagating to the specified AppsFlyer partners. | | `setAdditionalData` | Sets additional key-value data to send to AppsFlyer. | | `getAppsFlyerUID` | Get AppsFlyer’s unique device ID (created for every new install of an app). | | `anonymizeUser` | End User Opt-Out from AppsFlyer analytics (Anonymize user data). | | `stop` | Once this API is invoked, our SDK no longer communicates with our servers and stops functioning. Useful when implementing user opt-in/opt-out. | | `disableSKAdNetwork` | Opt-out of SKAdNetwork. | | `disableAdvertisingIdentifier` | Disables collection of various Advertising IDs by the SDK. This includes Apple Identity for Advertisers (IDFA), Google Advertising ID (GAID), OAID and Amazon Advertising ID (AAID). | | `disableCollectASA` | Opt-out of Apple Search Ads attributions. | | `setHost` | Set a custom host. | | `generateInviteLink` | Allowing your existing users to invite their friends and contacts as new users to your app. | | `validateAndLogInAppPurchaseAndroid` | API for server verification of in-app purchases. An af\_purchase event with the relevant values will be automatically logged if the validation is successful. | | `validateAndLogInAppPurchaseIos` | See the source definitions for current behavior. | | `getSdkVersion` | Get the AppsFlyer SDK version used in app. | | `enableFacebookDeferredApplinks` | Enable the collection of Facebook Deferred AppLinks. Requires Facebook SDK and Facebook app on target/client device. This API must be invoked before initializing the AppsFlyer SDK in order to function properly. | | `sendPushNotificationData` | Measure and get data from push-notification campaigns. | | `setCurrentDeviceLanguage` | Set the language of the device. The data will be displayed in Raw Data Reports. | | `logCrossPromoteImpression` | Logs an impression as part of a cross-promotion campaign. Make sure to use the promoted app ID as it appears in the AppsFlyer dashboard. | | `setUserEmails` | Set the user emails and encrypt them. | | `logLocation` | Manually log the location of the user. | | `setPhoneNumber` | Will be sent as an SHA-256 encrypted string. | | `setPartnerData` | Allows sending custom data for partner integration purposes. | | `logInvite` | Use to log a user-invite in-app event (af\_invite). | | `setDisableNetworkData` | Use to opt-out of collecting the network operator name (carrier) and sim operator name from the device. | | `enableTCFDataCollection` | Use to opt-in/out the automatic collection of consent data, for users who use a CMP. Flag value will be persisted between app sessions. | | `setConsentData` | Use this to set user consent data manually. If your app doesn’t use a CMP compatible with TCF v2.2, use the following method to manually provide the consent data directly to the SDK. | | `logAdRevenue` | By attributing ad revenue, app owners gain the complete view of user LTV and campaign ROI. Ad revenue is generated by displaying ads on rewarded videos, offer walls, interstitials, and banners in an app. You can use this method to log your ad revenue. | | `setConsentDataV2` | Use this to set user consent data manually. If your app doesn’t use a CMP compatible with TCF v2.2, use the following method to manually provide the consent data directly to the SDK. | | `isSDKStarted` | Use this method to check whether the AppsFlyer SDK has already been started in the current session. | | `isSDKStopped` | Use this method to check whether the AppsFlyer SDK is currently stopped. | | `disableAppSetId` | Disables AppSet ID collection. If called before SDK init, App Set ID will not be collected. If called after init, App Set ID will be collected but not sent in request payloads. Android only. | | `validateAndLogInAppPurchaseV2` | API for server verification of in-app purchases V2. An af\_purchase event with the relevant values will be automatically logged if the validation is successful. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-appsflyer](https://github.com/Cap-go/capacitor-appsflyer/). # Getting Started > Install @capgo/capacitor-appsflyer and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-appsflyer bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { AppsFlyer } from '@capgo/capacitor-appsflyer'; import type { AFAdRevenueData, AFAndroidInAppPurchase, AFAnonymizeUser, AFAppendToDeepLink, AFConsentData, AFConsentOptions, AFCuid, AFCurrency, AFData, AFDisable, AFEmails, AFEnableTCFDataCollection, AFEvent, AFFbDAL, AFFilters, AFHost, AFInit, AFIosInAppPurchase, AFLanguage, AFLatLng, AFLinkGenerator, AFLogInvite, AFOnelinkDomain, AFOnelinkID, AFPartnerData, AFPath, AFPhone, AFPromotion, AFPurchaseDetailsV2, AFPushPayload, AFUninstall, AFUrls, } from '@capgo/capacitor-appsflyer'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `initSDK` [Section titled “initSDK”](#initsdk) Use this method to initialize and start AppsFlyer SDK. This API should be called as soon as the app launches. ```typescript import { AppsFlyer } from '@capgo/capacitor-appsflyer'; await AppsFlyer.initSDK({} as AFInit); ``` ### `startSDK` [Section titled “startSDK”](#startsdk) Use this method to start AppsFlyer SDK, only on manual start mode. ```typescript import { AppsFlyer } from '@capgo/capacitor-appsflyer'; await AppsFlyer.startSDK(); ``` ### `logEvent` [Section titled “logEvent”](#logevent) Log an in-app event. ```typescript import { AppsFlyer } from '@capgo/capacitor-appsflyer'; await AppsFlyer.logEvent({} as AFEvent); ``` ### `setCustomerUserId` [Section titled “setCustomerUserId”](#setcustomeruserid) Setting your own customer ID enables you to cross-reference your own unique ID with AppsFlyer’s unique ID and other devices’ IDs. This ID is available in raw-data reports and in the Postback APIs for cross-referencing with your internal IDs. ```typescript import { AppsFlyer } from '@capgo/capacitor-appsflyer'; await AppsFlyer.setCustomerUserId({} as AFCuid); ``` ### `setCurrencyCode` [Section titled “setCurrencyCode”](#setcurrencycode) Sets the currency used for in-app purchases. Provide a three-character ISO 4217 code. ```typescript import { AppsFlyer } from '@capgo/capacitor-appsflyer'; await AppsFlyer.setCurrencyCode({} as AFCurrency); ``` ### `updateServerUninstallToken` [Section titled “updateServerUninstallToken”](#updateserveruninstalltoken) Pass GCM/FCM tokens on Android or APNs tokens on iOS when another plugin collected them. Use this to forward uninstall measurement tokens to AppsFlyer. ```typescript import { AppsFlyer } from '@capgo/capacitor-appsflyer'; await AppsFlyer.updateServerUninstallToken({} as AFUninstall); ``` ### `setAppInviteOneLink` [Section titled “setAppInviteOneLink”](#setappinviteonelink) Sets the OneLink ID used as the base link for invite attribution. ```typescript import { AppsFlyer } from '@capgo/capacitor-appsflyer'; await AppsFlyer.setAppInviteOneLink({} as AFOnelinkID); ``` ### `setOneLinkCustomDomain` [Section titled “setOneLinkCustomDomain”](#setonelinkcustomdomain) Registers branded OneLink domains so AppsFlyer can resolve attribution parameters hidden in short links. ```typescript import { AppsFlyer } from '@capgo/capacitor-appsflyer'; await AppsFlyer.setOneLinkCustomDomain({} as AFOnelinkDomain); ``` ### `appendParametersToDeepLinkingURL` [Section titled “appendParametersToDeepLinkingURL”](#appendparameterstodeeplinkingurl) Enables attribution for App Links deep links without OneLink. Call this method before `startSDK()`. Include at least `pid` and `is_retargeting=true` in the parameters map. ```typescript import { AppsFlyer } from '@capgo/capacitor-appsflyer'; await AppsFlyer.appendParametersToDeepLinkingURL({} as AFAppendToDeepLink); ``` ### `setResolveDeepLinkURLs` [Section titled “setResolveDeepLinkURLs”](#setresolvedeeplinkurls) Use this when an AppsFlyer OneLink is wrapped inside another Universal Link. It lets the SDK resolve the wrapped URL so deep linking still works correctly. ```typescript import { AppsFlyer } from '@capgo/capacitor-appsflyer'; await AppsFlyer.setResolveDeepLinkURLs({} as AFUrls); ``` ### `addPushNotificationDeepLinkPath` [Section titled “addPushNotificationDeepLinkPath”](#addpushnotificationdeeplinkpath) Configures how the SDK extracts deep link values from push notification payloads. ```typescript import { AppsFlyer } from '@capgo/capacitor-appsflyer'; await AppsFlyer.addPushNotificationDeepLinkPath({} as AFPath); ``` ### `setSharingFilter` [Section titled “setSharingFilter”](#setsharingfilter) Stops events from propagating to the specified AppsFlyer partners. ```typescript import { AppsFlyer } from '@capgo/capacitor-appsflyer'; await AppsFlyer.setSharingFilter({} as AFFilters); ``` ### `setSharingFilterForAllPartners` [Section titled “setSharingFilterForAllPartners”](#setsharingfilterforallpartners) Stops events from propagating to all AppsFlyer partners. Overwrites setSharingFilter. ```typescript import { AppsFlyer } from '@capgo/capacitor-appsflyer'; await AppsFlyer.setSharingFilterForAllPartners(); ``` ### `setSharingFilterForPartners` [Section titled “setSharingFilterForPartners”](#setsharingfilterforpartners) Stops events from propagating to the specified AppsFlyer partners. ```typescript import { AppsFlyer } from '@capgo/capacitor-appsflyer'; await AppsFlyer.setSharingFilterForPartners({} as AFFilters); ``` ### `setAdditionalData` [Section titled “setAdditionalData”](#setadditionaldata) Sets additional key-value data to send to AppsFlyer. ```typescript import { AppsFlyer } from '@capgo/capacitor-appsflyer'; await AppsFlyer.setAdditionalData({} as AFData); ``` ### `getAppsFlyerUID` [Section titled “getAppsFlyerUID”](#getappsflyeruid) Get AppsFlyer’s unique device ID (created for every new install of an app). ```typescript import { AppsFlyer } from '@capgo/capacitor-appsflyer'; await AppsFlyer.getAppsFlyerUID(); ``` ### `anonymizeUser` [Section titled “anonymizeUser”](#anonymizeuser) End User Opt-Out from AppsFlyer analytics (Anonymize user data). ```typescript import { AppsFlyer } from '@capgo/capacitor-appsflyer'; await AppsFlyer.anonymizeUser({} as AFAnonymizeUser); ``` ### `stop` [Section titled “stop”](#stop) Once this API is invoked, our SDK no longer communicates with our servers and stops functioning. Useful when implementing user opt-in/opt-out. ```typescript import { AppsFlyer } from '@capgo/capacitor-appsflyer'; await AppsFlyer.stop(); ``` ### `disableSKAdNetwork` [Section titled “disableSKAdNetwork”](#disableskadnetwork) Opt-out of SKAdNetwork ```typescript import { AppsFlyer } from '@capgo/capacitor-appsflyer'; await AppsFlyer.disableSKAdNetwork({} as AFDisable); ``` ### `disableAdvertisingIdentifier` [Section titled “disableAdvertisingIdentifier”](#disableadvertisingidentifier) Disables collection of various Advertising IDs by the SDK. This includes Apple Identity for Advertisers (IDFA), Google Advertising ID (GAID), OAID and Amazon Advertising ID (AAID). ```typescript import { AppsFlyer } from '@capgo/capacitor-appsflyer'; await AppsFlyer.disableAdvertisingIdentifier({} as AFDisable); ``` ### `disableCollectASA` [Section titled “disableCollectASA”](#disablecollectasa) Opt-out of Apple Search Ads attributions. ```typescript import { AppsFlyer } from '@capgo/capacitor-appsflyer'; await AppsFlyer.disableCollectASA({} as AFDisable); ``` ### `setHost` [Section titled “setHost”](#sethost) Set a custom host. ```typescript import { AppsFlyer } from '@capgo/capacitor-appsflyer'; await AppsFlyer.setHost({} as AFHost); ``` ### `generateInviteLink` [Section titled “generateInviteLink”](#generateinvitelink) Allowing your existing users to invite their friends and contacts as new users to your app ```typescript import { AppsFlyer } from '@capgo/capacitor-appsflyer'; await AppsFlyer.generateInviteLink({} as AFLinkGenerator); ``` ### `validateAndLogInAppPurchaseAndroid` [Section titled “validateAndLogInAppPurchaseAndroid”](#validateandloginapppurchaseandroid) API for server verification of in-app purchases. An af\_purchase event with the relevant values will be automatically logged if the validation is successful. ```typescript import { AppsFlyer } from '@capgo/capacitor-appsflyer'; await AppsFlyer.validateAndLogInAppPurchaseAndroid({} as AFAndroidInAppPurchase); ``` ### `validateAndLogInAppPurchaseIos` [Section titled “validateAndLogInAppPurchaseIos”](#validateandloginapppurchaseios) See the source definitions for the current contract. ```typescript import { AppsFlyer } from '@capgo/capacitor-appsflyer'; await AppsFlyer.validateAndLogInAppPurchaseIos({} as AFIosInAppPurchase); ``` ### `getSdkVersion` [Section titled “getSdkVersion”](#getsdkversion) Get the AppsFlyer SDK version used in app. ```typescript import { AppsFlyer } from '@capgo/capacitor-appsflyer'; await AppsFlyer.getSdkVersion(); ``` ### `enableFacebookDeferredApplinks` [Section titled “enableFacebookDeferredApplinks”](#enablefacebookdeferredapplinks) Enable the collection of Facebook Deferred AppLinks. Requires Facebook SDK and Facebook app on target/client device. This API must be invoked before initializing the AppsFlyer SDK in order to function properly. ```typescript import { AppsFlyer } from '@capgo/capacitor-appsflyer'; await AppsFlyer.enableFacebookDeferredApplinks({} as AFFbDAL); ``` ### `sendPushNotificationData` [Section titled “sendPushNotificationData”](#sendpushnotificationdata) Measure and get data from push-notification campaigns. ```typescript import { AppsFlyer } from '@capgo/capacitor-appsflyer'; await AppsFlyer.sendPushNotificationData({} as AFPushPayload); ``` ### `setCurrentDeviceLanguage` [Section titled “setCurrentDeviceLanguage”](#setcurrentdevicelanguage) Set the language of the device. The data will be displayed in Raw Data Reports ```typescript import { AppsFlyer } from '@capgo/capacitor-appsflyer'; await AppsFlyer.setCurrentDeviceLanguage({} as AFLanguage); ``` ### `logCrossPromoteImpression` [Section titled “logCrossPromoteImpression”](#logcrosspromoteimpression) Logs an impression as part of a cross-promotion campaign. Make sure to use the promoted app ID as it appears in the AppsFlyer dashboard. ```typescript import { AppsFlyer } from '@capgo/capacitor-appsflyer'; await AppsFlyer.logCrossPromoteImpression({} as AFPromotion); ``` ### `setUserEmails` [Section titled “setUserEmails”](#setuseremails) Set the user emails and encrypt them. ```typescript import { AppsFlyer } from '@capgo/capacitor-appsflyer'; await AppsFlyer.setUserEmails({} as AFEmails); ``` ### `logLocation` [Section titled “logLocation”](#loglocation) Manually log the location of the user ```typescript import { AppsFlyer } from '@capgo/capacitor-appsflyer'; await AppsFlyer.logLocation({} as AFLatLng); ``` ### `setPhoneNumber` [Section titled “setPhoneNumber”](#setphonenumber) Will be sent as an SHA-256 encrypted string. ```typescript import { AppsFlyer } from '@capgo/capacitor-appsflyer'; await AppsFlyer.setPhoneNumber({} as AFPhone); ``` ### `setPartnerData` [Section titled “setPartnerData”](#setpartnerdata) Allows sending custom data for partner integration purposes. ```typescript import { AppsFlyer } from '@capgo/capacitor-appsflyer'; await AppsFlyer.setPartnerData({} as AFPartnerData); ``` ### `logInvite` [Section titled “logInvite”](#loginvite) Use to log a user-invite in-app event (af\_invite). ```typescript import { AppsFlyer } from '@capgo/capacitor-appsflyer'; await AppsFlyer.logInvite({} as AFLogInvite); ``` ### `setDisableNetworkData` [Section titled “setDisableNetworkData”](#setdisablenetworkdata) Use to opt-out of collecting the network operator name (carrier) and sim operator name from the device. ```typescript import { AppsFlyer } from '@capgo/capacitor-appsflyer'; await AppsFlyer.setDisableNetworkData({} as AFDisable); ``` ### `enableTCFDataCollection` [Section titled “enableTCFDataCollection”](#enabletcfdatacollection) Use to opt-in/out the automatic collection of consent data, for users who use a CMP. Flag value will be persisted between app sessions. ```typescript import { AppsFlyer } from '@capgo/capacitor-appsflyer'; await AppsFlyer.enableTCFDataCollection({} as AFEnableTCFDataCollection); ``` ### `setConsentData` [Section titled “setConsentData”](#setconsentdata) Use this to set user consent data manually. If your app doesn’t use a CMP compatible with TCF v2.2, use the following method to manually provide the consent data directly to the SDK. ```typescript import { AppsFlyer } from '@capgo/capacitor-appsflyer'; await AppsFlyer.setConsentData({} as AFConsentData); ``` ### `logAdRevenue` [Section titled “logAdRevenue”](#logadrevenue) By attributing ad revenue, app owners gain the complete view of user LTV and campaign ROI. Ad revenue is generated by displaying ads on rewarded videos, offer walls, interstitials, and banners in an app. You can use this method to log your ad revenue. ```typescript import { AppsFlyer } from '@capgo/capacitor-appsflyer'; await AppsFlyer.logAdRevenue({} as AFAdRevenueData); ``` ### `setConsentDataV2` [Section titled “setConsentDataV2”](#setconsentdatav2) Use this to set user consent data manually. If your app doesn’t use a CMP compatible with TCF v2.2, use the following method to manually provide the consent data directly to the SDK. ```typescript import { AppsFlyer } from '@capgo/capacitor-appsflyer'; await AppsFlyer.setConsentDataV2({} as AFConsentOptions); ``` ### `isSDKStarted` [Section titled “isSDKStarted”](#issdkstarted) Use this method to check whether the AppsFlyer SDK has already been started in the current session. ```typescript import { AppsFlyer } from '@capgo/capacitor-appsflyer'; await AppsFlyer.isSDKStarted(); ``` ### `isSDKStopped` [Section titled “isSDKStopped”](#issdkstopped) Use this method to check whether the AppsFlyer SDK is currently stopped. ```typescript import { AppsFlyer } from '@capgo/capacitor-appsflyer'; await AppsFlyer.isSDKStopped(); ``` ### `disableAppSetId` [Section titled “disableAppSetId”](#disableappsetid) Disables AppSet ID collection. If called before SDK init, App Set ID will not be collected. If called after init, App Set ID will be collected but not sent in request payloads. Android only. ```typescript import { AppsFlyer } from '@capgo/capacitor-appsflyer'; await AppsFlyer.disableAppSetId(); ``` ### `validateAndLogInAppPurchaseV2` [Section titled “validateAndLogInAppPurchaseV2”](#validateandloginapppurchasev2) API for server verification of in-app purchases V2. An af\_purchase event with the relevant values will be automatically logged if the validation is successful. ```typescript import { AppsFlyer } from '@capgo/capacitor-appsflyer'; await AppsFlyer.validateAndLogInAppPurchaseV2({} as AFPurchaseDetailsV2); ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-audio-recorder > Capacitor plugin contract for recording audio. ## Overview [Section titled “Overview”](#overview) Capacitor plugin contract for recording audio. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `startRecording` - Start recording audio using the device microphone. * `pauseRecording` - Pause the ongoing recording. Only available on Android (API 24+), iOS, and Web. * `resumeRecording` - Resume a previously paused recording. * `stopRecording` - Stop the current recording and persist the recorded audio. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | --------------------- | ----------------------------------------------------------------------------------------------------- | | `startRecording` | Start recording audio using the device microphone. | | `pauseRecording` | Pause the ongoing recording. Only available on Android (API 24+), iOS, and Web. | | `resumeRecording` | Resume a previously paused recording. | | `stopRecording` | Stop the current recording and persist the recorded audio. | | `cancelRecording` | Cancel the current recording and discard any captured audio. | | `getRecordingStatus` | Retrieve the current recording status. | | `getCurrentAmplitude` | Retrieve the current input amplitude (microphone level) as a normalized number in the `[0, 1]` range. | | `checkPermissions` | Return the current permission state for accessing the microphone. | | `requestPermissions` | Request permission to access the microphone. | | `addListener` | Listen for recording errors. | | `addListener` | Listen for pause events emitted when a recording is paused. | | `addListener` | Listen for recording completion events. | | `removeAllListeners` | Remove all registered listeners. | | `getPluginVersion` | Get the native Capacitor plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-audio-recorder](https://github.com/Cap-go/capacitor-audio-recorder/). # Getting Started > Install @capgo/capacitor-audio-recorder and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-audio-recorder bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { CapacitorAudioRecorder } from '@capgo/capacitor-audio-recorder'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `startRecording` [Section titled “startRecording”](#startrecording) Start recording audio using the device microphone. ```typescript import { CapacitorAudioRecorder } from '@capgo/capacitor-audio-recorder'; await CapacitorAudioRecorder.startRecording(); ``` ### `pauseRecording` [Section titled “pauseRecording”](#pauserecording) Pause the ongoing recording. Only available on Android (API 24+), iOS, and Web. ```typescript import { CapacitorAudioRecorder } from '@capgo/capacitor-audio-recorder'; await CapacitorAudioRecorder.pauseRecording(); ``` ### `resumeRecording` [Section titled “resumeRecording”](#resumerecording) Resume a previously paused recording. ```typescript import { CapacitorAudioRecorder } from '@capgo/capacitor-audio-recorder'; await CapacitorAudioRecorder.resumeRecording(); ``` ### `stopRecording` [Section titled “stopRecording”](#stoprecording) Stop the current recording and persist the recorded audio. ```typescript import { CapacitorAudioRecorder } from '@capgo/capacitor-audio-recorder'; await CapacitorAudioRecorder.stopRecording(); ``` ### `cancelRecording` [Section titled “cancelRecording”](#cancelrecording) Cancel the current recording and discard any captured audio. ```typescript import { CapacitorAudioRecorder } from '@capgo/capacitor-audio-recorder'; await CapacitorAudioRecorder.cancelRecording(); ``` ### `getRecordingStatus` [Section titled “getRecordingStatus”](#getrecordingstatus) Retrieve the current recording status. ```typescript import { CapacitorAudioRecorder } from '@capgo/capacitor-audio-recorder'; await CapacitorAudioRecorder.getRecordingStatus(); ``` ### `getCurrentAmplitude` [Section titled “getCurrentAmplitude”](#getcurrentamplitude) Retrieve the current input amplitude (microphone level) as a normalized number in the `[0, 1]` range. Intended for driving live visualizations such as VU meters or waveforms while recording. Returns `0` when no recording is active. Designed for UI-rate polling — a 60–100 ms interval is a good starting point for a waveform. Avoid calling it in a tight loop; each call crosses the JS/native bridge. ```typescript import { CapacitorAudioRecorder } from '@capgo/capacitor-audio-recorder'; await CapacitorAudioRecorder.getCurrentAmplitude(); ``` ### `checkPermissions` [Section titled “checkPermissions”](#checkpermissions) Return the current permission state for accessing the microphone. ```typescript import { CapacitorAudioRecorder } from '@capgo/capacitor-audio-recorder'; await CapacitorAudioRecorder.checkPermissions(); ``` ### `requestPermissions` [Section titled “requestPermissions”](#requestpermissions) Request permission to access the microphone. ```typescript import { CapacitorAudioRecorder } from '@capgo/capacitor-audio-recorder'; await CapacitorAudioRecorder.requestPermissions(); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `StartRecordingOptions` [Section titled “StartRecordingOptions”](#startrecordingoptions) Options accepted by . ```typescript export interface StartRecordingOptions { /** * The audio session category options for recording. Only available on iOS. * * @since 1.0.0 */ audioSessionCategoryOptions?: AudioSessionCategoryOption[]; /** * The audio session mode for recording. Only available on iOS. * * @since 1.0.0 */ audioSessionMode?: AudioSessionMode; /** * The audio bit rate in bytes per second. * Only available on Android and iOS. * * @since 1.0.0 */ bitRate?: number; /** * The audio sample rate in Hz. * Only available on Android and iOS. * * @since 1.0.0 */ sampleRate?: number; } ``` ### `StopRecordingResult` [Section titled “StopRecordingResult”](#stoprecordingresult) Result returned by . ```typescript export interface StopRecordingResult { /** * The recorded audio as a Blob. Only available on Web. * * @since 1.0.0 */ blob?: Blob; /** * The duration of the recording in milliseconds. * * @since 1.0.0 */ duration?: number; /** * The URI pointing to the recorded file. Only available on Android and iOS. * * @since 1.0.0 */ uri?: string; } ``` ### `GetRecordingStatusResult` [Section titled “GetRecordingStatusResult”](#getrecordingstatusresult) Result returned by . ```typescript export interface GetRecordingStatusResult { /** * The current recording status. * * @since 1.0.0 */ status: RecordingStatus; } ``` ### `GetCurrentAmplitudeResult` [Section titled “GetCurrentAmplitudeResult”](#getcurrentamplituderesult) Result returned by . ```typescript export interface GetCurrentAmplitudeResult { /** * The current input amplitude normalized to the `[0, 1]` range, where `0` * represents silence and `1` represents the maximum level the platform can * report. The value is `0` when no recording is active. * * Note: the source signal differs between platforms — Android reports the * peak sample amplitude since the last call, iOS reports the average power * in dB converted to linear, and Web reports the RMS of the latest frame. * Consumers that need cross-platform parity may want to apply a * per-platform scaling curve. * * @since 8.1.0 */ value: number; } ``` ### `PermissionStatus` [Section titled “PermissionStatus”](#permissionstatus) Permission information returned by and . ```typescript export interface PermissionStatus { /** * The permission state for audio recording. * * @since 1.0.0 */ recordAudio: PermissionState; } ``` ### `RecordingErrorEvent` [Section titled “RecordingErrorEvent”](#recordingerrorevent) Event emitted when an error occurs during recording. ```typescript export interface RecordingErrorEvent { /** * The error message. * * @since 1.0.0 */ message: string; } ``` ### `RecordingStoppedEvent` [Section titled “RecordingStoppedEvent”](#recordingstoppedevent) Event emitted when a recording completes. ```typescript export type RecordingStoppedEvent = StopRecordingResult; ``` ### `AudioSessionCategoryOption` [Section titled “AudioSessionCategoryOption”](#audiosessioncategoryoption) Audio session category options available on iOS. ```typescript export enum AudioSessionCategoryOption { AllowAirPlay = 'ALLOW_AIR_PLAY', AllowBluetooth = 'ALLOW_BLUETOOTH', AllowBluetoothA2DP = 'ALLOW_BLUETOOTH_A2DP', DefaultToSpeaker = 'DEFAULT_TO_SPEAKER', DuckOthers = 'DUCK_OTHERS', InterruptSpokenAudioAndMixWithOthers = 'INTERRUPT_SPOKEN_AUDIO_AND_MIX_WITH_OTHERS', MixWithOthers = 'MIX_WITH_OTHERS', OverrideMutedMicrophoneInterruption = 'OVERRIDE_MUTED_MICROPHONE_INTERRUPTION', } ``` ### `AudioSessionMode` [Section titled “AudioSessionMode”](#audiosessionmode) Audio session modes available on iOS. ```typescript export enum AudioSessionMode { Default = 'DEFAULT', GameChat = 'GAME_CHAT', Measurement = 'MEASUREMENT', SpokenAudio = 'SPOKEN_AUDIO', VideoChat = 'VIDEO_CHAT', VideoRecording = 'VIDEO_RECORDING', VoiceChat = 'VOICE_CHAT', } ``` ### `RecordingStatus` [Section titled “RecordingStatus”](#recordingstatus) The recording status. ```typescript export enum RecordingStatus { Inactive = 'INACTIVE', Recording = 'RECORDING', Paused = 'PAUSED', } ``` ### `PermissionState` [Section titled “PermissionState”](#permissionstate) Platform permission states supported by Capacitor. ```typescript export type PermissionState = 'prompt' | 'prompt-with-rationale' | 'granted' | 'denied'; ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-audio-session > iOS-only plugin to query and control the audio session output and listen to route changes and interruptions. ## Overview [Section titled “Overview”](#overview) iOS-only plugin to query and control the audio session output and listen to route changes and interruptions. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `currentOutputs` - Get the current active audio output routes. * `overrideOutput` - Override the current audio output route. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------ | -------------------------------------------------------------------------- | | `currentOutputs` | Get the current active audio output routes. | | `overrideOutput` | Override the current audio output route. | | `addListener` | Listen for audio route changes (e.g. headset connected/disconnected). | | `addListener` | Listen for audio session interruptions (e.g. incoming call) and their end. | | `getPluginVersion` | Get the native Capacitor plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-audiosession](https://github.com/Cap-go/capacitor-audiosession/). # Getting Started > Install @capgo/capacitor-audio-session and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-audio-session bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { AudioSession } from '@capgo/capacitor-audio-session'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `currentOutputs` [Section titled “currentOutputs”](#currentoutputs) Get the current active audio output routes. On web and non-iOS platforms, this resolves to an empty array. ```typescript import { AudioSession } from '@capgo/capacitor-audio-session'; await AudioSession.currentOutputs(); ``` ### `overrideOutput` [Section titled “overrideOutput”](#overrideoutput) Override the current audio output route. Use `speaker` to force playback through the built-in speaker, or `default` to restore the system-selected route. ```typescript import { AudioSession } from '@capgo/capacitor-audio-session'; await AudioSession.overrideOutput({} as OutputOverrideType); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `AudioSessionPorts` [Section titled “AudioSessionPorts”](#audiosessionports) Available audio output routes on iOS. ```typescript export enum AudioSessionPorts { AIR_PLAY = 'airplay', BLUETOOTH_LE = 'bluetooth-le', BLUETOOTH_HFP = 'bluetooth-hfp', BLUETOOTH_A2DP = 'bluetooth-a2dp', BUILT_IN_SPEAKER = 'builtin-speaker', BUILT_IN_RECEIVER = 'builtin-receiver', HDMI = 'hdmi', HEADPHONES = 'headphones', LINE_OUT = 'line-out', } ``` ### `OutputOverrideType` [Section titled “OutputOverrideType”](#outputoverridetype) Output override type. - `default`: Use the system-selected route. - `speaker`: Force playback through the built-in speaker. ```typescript export type OutputOverrideType = 'default' | 'speaker'; ``` ### `OverrideResult` [Section titled “OverrideResult”](#overrideresult) Result of an output override request. ```typescript export type OverrideResult = { success: boolean; message: string; }; ``` ### `RouteChangeListener` [Section titled “RouteChangeListener”](#routechangelistener) Listener called when the audio route changes. ```typescript export type RouteChangeListener = (reason: RouteChangeReasons) => void; ``` ### `InterruptionListener` [Section titled “InterruptionListener”](#interruptionlistener) Listener called when the audio session is interrupted or ends. ```typescript export type InterruptionListener = (type: InterruptionTypes) => void; ``` ### `RouteChangeReasons` [Section titled “RouteChangeReasons”](#routechangereasons) ```typescript export enum RouteChangeReasons { NEW_DEVICE_AVAILABLE = 'new-device-available', OLD_DEVICE_UNAVAILABLE = 'old-device-unavailable', CATEGORY_CHANGE = 'category-change', OVERRIDE = 'override', WAKE_FROM_SLEEP = 'wake-from-sleep', NO_SUITABLE_ROUTE_FOR_CATEGORY = 'no-suitable-route-for-category', ROUTE_CONFIGURATION_CHANGE = 'route-config-change', UNKNOWN = 'unknown', } ``` ### `InterruptionTypes` [Section titled “InterruptionTypes”](#interruptiontypes) ```typescript export enum InterruptionTypes { BEGAN = 'began', ENDED = 'ended', } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-autofill-save-password > Prompt to display dialog for saving password to keychain from webview app. ## Overview [Section titled “Overview”](#overview) Prompt to display dialog for saving password to keychain from webview app. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `promptDialog` - Save a password to the keychain. * `readPassword` - Read a password from the keychain. Requires the developer to setup associated domain for the app for iOS. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------ | --------------------------------------------------------------------------------------------------------- | | `promptDialog` | Save a password to the keychain. | | `readPassword` | Read a password from the keychain. Requires the developer to setup associated domain for the app for iOS. | | `getPluginVersion` | Get the native Capacitor plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-autofill-save-password](https://github.com/Cap-go/capacitor-autofill-save-password/). # Getting Started > Install @capgo/capacitor-autofill-save-password and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-autofill-save-password bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { SavePassword } from '@capgo/capacitor-autofill-save-password'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `promptDialog` [Section titled “promptDialog”](#promptdialog) Save a password to the keychain. ```typescript import { SavePassword } from '@capgo/capacitor-autofill-save-password'; await SavePassword.promptDialog({ username: 'your-username', password: 'your-password' }); ``` ### `readPassword` [Section titled “readPassword”](#readpassword) Read a password from the keychain. Requires the developer to setup associated domain for the app for iOS. ```typescript import { SavePassword } from '@capgo/capacitor-autofill-save-password'; await SavePassword.readPassword(); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `Options` [Section titled “Options”](#options) ```typescript export interface Options { /** * The username to save. */ username: string; /** * The password to save. */ password: string; /** * The url to save the password for. (For example: "console.capgo.app") * iOS only. */ url?: string; } ``` ### `ReadPasswordResult` [Section titled “ReadPasswordResult”](#readpasswordresult) ```typescript export interface ReadPasswordResult { /** * The username of the password. */ username: string; /** * The password of the password. */ password: string; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/background-geolocation > Accurate background location tracking, native geofence enter/exit events, and transition webhooks for Capacitor apps. ## Overview [Section titled “Overview”](#overview) Use `@capgo/background-geolocation` when your Capacitor app needs precise location updates in the foreground or background, native circular geofences on iOS and Android, and backend delivery for geofence transitions when the WebView is suspended. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `start` - Stream accurate foreground or background location updates. * `stop` - Stop active location tracking cleanly. * `openSettings` - Send users to native location settings when permissions need attention. * `setPlannedRoute` - Play a native sound when the user deviates from a planned route. * `setupGeofencing` - Configure native geofence defaults and optional transition webhook delivery. * `addGeofence` - Monitor a circular iOS or Android geofence region by identifier. * `removeGeofence` / `removeAllGeofences` - Stop monitoring one or all registered geofences. * `getMonitoredGeofences` - List region identifiers currently monitored by the native layer. * `geofenceTransition` listener - Receive enter and exit events while the app is active. * `geofenceError` listener - Handle native monitoring errors without changing the transition event shape. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | | `start` | Streams accurate foreground or background location updates. | | `stop` | Stops location updates. | | `openSettings` | Opens the device’s location settings page. Useful for directing users to enable location services or adjust permissions. | | `setPlannedRoute` | Plays a native sound when the user deviates from a planned route. | | `setupGeofencing` | Configures geofence defaults and optional native transition POST delivery. | | `addGeofence` | Starts monitoring a circular geofence on iOS and Android. | | `removeGeofence` | Stops monitoring one geofence by identifier. | | `removeAllGeofences` | Stops monitoring all geofences registered by this plugin. | | `getMonitoredGeofences` | Returns the identifiers currently monitored by the native layer. | | `addListener('geofenceTransition', ...)` | Receives geofence enter and exit events while the app is alive. | | `addListener('geofenceError', ...)` | Receives native geofence monitoring errors while the app is alive. | | `getPluginVersion` | Get the native Capacitor plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-background-geolocation](https://github.com/Cap-go/capacitor-background-geolocation/). # Getting Started > Install @capgo/background-geolocation for background location tracking and native geofencing. `@capgo/background-geolocation` combines precise background location tracking with native geofencing for iOS and Android. Use it for delivery zones, stores, job sites, campuses, check-ins, route alerts, and any workflow that needs enter or exit events even when the WebView is not running. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/background-geolocation bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { BackgroundGeolocation } from '@capgo/background-geolocation'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `start` [Section titled “start”](#start) To start listening for changes in the device’s location, call this method. A Promise is returned to indicate that it finished the call. The callback will be called every time a new location is available, or if there was an error when calling this method. Don’t rely on promise rejection for this. ```typescript import { BackgroundGeolocation } from '@capgo/background-geolocation'; await BackgroundGeolocation.start( { backgroundMessage: "App is using your location in the background", backgroundTitle: "Location Service", requestPermissions: true, stale: false, distanceFilter: 10 }, (location, error) => { if (error) { console.error('Location error:', error); return; } if (location) { console.log('New location:', location.latitude, location.longitude); } } ); ``` ### `stop` [Section titled “stop”](#stop) Stops location updates. ```typescript import { BackgroundGeolocation } from '@capgo/background-geolocation'; await BackgroundGeolocation.stop(); ``` ### `openSettings` [Section titled “openSettings”](#opensettings) Opens the device’s location settings page. Useful for directing users to enable location services or adjust permissions. ```typescript import { BackgroundGeolocation } from '@capgo/background-geolocation'; // Direct user to location settings await BackgroundGeolocation.openSettings(); ``` ### `setPlannedRoute` [Section titled “setPlannedRoute”](#setplannedroute) Plays a sound file when the user deviates from the planned route. This should be used to play a sound (in the background too, only for native). ```typescript import { BackgroundGeolocation } from '@capgo/background-geolocation'; await BackgroundGeolocation.setPlannedRoute({ soundFile: "notification.mp3", route: [[-74.0060, 40.7128], [-118.2437, 34.0522]] }); ``` ### Native geofencing [Section titled “Native geofencing”](#native-geofencing) Geofencing runs in the native layer, so iOS and Android can trigger enter and exit events without relying on the WebView to stay awake. Configure an HTTP or HTTPS webhook URL when your backend must receive transitions even while the app UI is suspended. ```typescript import { BackgroundGeolocation } from '@capgo/background-geolocation'; await BackgroundGeolocation.setupGeofencing({ url: 'https://api.example.com/geofences', notifyOnEntry: true, notifyOnExit: true, payload: { userId: '123' }, }); await BackgroundGeolocation.addGeofence({ identifier: 'store-42', latitude: 37.33182, longitude: -122.03118, radius: 150, payload: { storeId: '42' }, }); const handle = await BackgroundGeolocation.addListener( 'geofenceTransition', (event) => { console.log(event.identifier, event.transition); }, ); const errorHandle = await BackgroundGeolocation.addListener( 'geofenceError', (event) => { console.error(event.identifier, event.message); }, ); const { regions } = await BackgroundGeolocation.getMonitoredGeofences(); console.log(regions); await BackgroundGeolocation.removeGeofence({ identifier: 'store-42' }); await handle.remove(); await errorHandle.remove(); ``` On iOS, geofencing requires Always location authorization. On Android 10 and newer, add background location permission to your app manifest when you need background geofencing: ```xml ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `StartOptions` [Section titled “StartOptions”](#startoptions) The options for configuring for location updates. ```typescript export interface StartOptions { /** * If the "backgroundMessage" option is defined, the plugin will * provide location updates whether the app is in the background or the * foreground. If it is not defined, location updates are only * guaranteed in the foreground. This is true on both platforms. * * On Android, a notification must be shown to continue receiving * location updates in the background. This option specifies the text of * that notification. * * @since 7.0.9 * @example "Getting your location to provide better service" */ backgroundMessage?: string; /** * The title of the notification mentioned above. * * @since 7.0.9 * @default "Using your location" * @example "Location Service" */ backgroundTitle?: string; /** * Whether permissions should be requested from the user automatically, * if they are not already granted. * * @since 7.0.9 * @default true * @example * // Auto-request permissions * requestPermissions: true * * // Don't auto-request, handle manually * requestPermissions: false */ requestPermissions?: boolean; /** * If "true", stale locations may be delivered while the device * obtains a GPS fix. You are responsible for checking the "time" * property. If "false", locations are guaranteed to be up to date. * * @since 7.0.9 * @default false * @example * // Allow stale locations for faster initial response * stale: true * * // Only fresh locations * stale: false */ stale?: boolean; /** * The distance in meters that the device must move before a new location update is triggered. * This is used to filter out small movements and reduce the number of updates. * * @since 7.0.9 * @default 0 * @example * // Update every 10 meters * distanceFilter: 10 * * // Update on any movement * distanceFilter: 0 */ distanceFilter?: number; } ``` ### `Location` [Section titled “Location”](#location) Represents a geographical location with various attributes. Contains all the standard location properties returned by GPS/network providers. ```typescript export interface Location { /** * Latitude in degrees. * Range: -90.0 to +90.0 * * @since 7.0.0 * @example 40.7128 */ latitude: number; /** * Longitude in degrees. * Range: -180.0 to +180.0 * * @since 7.0.0 * @example -74.0060 */ longitude: number; /** * Radius of horizontal uncertainty in metres, with 68% confidence. * Lower values indicate more accurate location. * * @since 7.0.0 * @example 5.0 */ accuracy: number; /** * Metres above sea level (or null if not available). * * @since 7.0.0 * @example 10.5 */ altitude: number | null; /** * Vertical uncertainty in metres, with 68% confidence (or null if not available). * * @since 7.0.0 * @example 3.0 */ altitudeAccuracy: number | null; /** * `true` if the location was simulated by software, rather than GPS. * Useful for detecting mock locations in development or testing. * * @since 7.0.0 * @example false */ simulated: boolean; /** * Deviation from true north in degrees (or null if not available). * Range: 0.0 to 360.0 * * @since 7.0.0 * @example 45.5 */ bearing: number | null; /** * Speed in metres per second (or null if not available). * * @since 7.0.0 * @example 2.5 */ speed: number | null; /** * Time the location was produced, in milliseconds since the unix epoch. * Use this to check if a location is stale when using stale: true. * * @since 7.0.0 * @example 1640995200000 */ time: number | null; } ``` ### `CallbackError` [Section titled “CallbackError”](#callbackerror) Error object that may be passed to the location start callback. Extends the standard Error with optional error codes. ```typescript export interface CallbackError extends Error { /** * Optional error code for more specific error handling. * * @since 7.0.0 * @example "PERMISSION_DENIED" */ code?: string; } ``` ### `SetPlannedRouteOptions` [Section titled “SetPlannedRouteOptions”](#setplannedrouteoptions) ```typescript export interface SetPlannedRouteOptions { /** * The name of the sound file to play. * Must be a valid sound relative path in the app's public folder to work for both web and native platforms. * There's no need to include the public folder in the path. * @since 7.0.10 * @example "notification.mp3" * */ soundFile: string; /** * The planned route as an array of longitude and latitude pairs. * Each pair represents a point on the route. * This is used to define a route that the user can follow. * The route is used to play a sound when the user deviates from it. * @since 7.0.11 * @example [[-74.0060, 40.7128], [-118.2437, 34.0522]] */ route: [number, number][]; /** * The distance in meters that the user must deviate from the planned route to trigger the sound. * This is used to determine how far off the route the user can be before the sound is played. * If not specified, a default value of 50 meters is used. * @since 7.0.11 * @default 50 * @example 50 */ distance: number; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-barometer > Capacitor plugin contract for working with the device barometer sensor. ## Overview [Section titled “Overview”](#overview) Capacitor plugin contract for working with the device barometer sensor. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `getMeasurement` - Get the most recent barometer reading captured by the native layer. * `isAvailable` - Check if the current device includes a barometer sensor. * `startMeasurementUpdates` - Begin streaming barometer updates to the JavaScript layer. * `stopMeasurementUpdates` - Stop the continuous updates started via . ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------------- | ------------------------------------------------------------------------ | | `getMeasurement` | Get the most recent barometer reading captured by the native layer. | | `isAvailable` | Check if the current device includes a barometer sensor. | | `startMeasurementUpdates` | Begin streaming barometer updates to the JavaScript layer. | | `stopMeasurementUpdates` | Stop the continuous updates started via . | | `checkPermissions` | Return the current permission state for accessing barometer data. | | `requestPermissions` | Request permission to access barometer data if required by the platform. | | `addListener` | Listen for pressure updates. | | `removeAllListeners` | Remove all registered listeners for this plugin. | | `getPluginVersion` | Get the native Capacitor plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-barometer](https://github.com/Cap-go/capacitor-barometer/). # Getting Started > Install @capgo/capacitor-barometer and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-barometer bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { CapacitorBarometer } from '@capgo/capacitor-barometer'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `getMeasurement` [Section titled “getMeasurement”](#getmeasurement) Get the most recent barometer reading captured by the native layer. ```typescript import { CapacitorBarometer } from '@capgo/capacitor-barometer'; await CapacitorBarometer.getMeasurement(); ``` ### `isAvailable` [Section titled “isAvailable”](#isavailable) Check if the current device includes a barometer sensor. ```typescript import { CapacitorBarometer } from '@capgo/capacitor-barometer'; await CapacitorBarometer.isAvailable(); ``` ### `startMeasurementUpdates` [Section titled “startMeasurementUpdates”](#startmeasurementupdates) Begin streaming barometer updates to the JavaScript layer. Call with the `measurement` event to receive the updates. ```typescript import { CapacitorBarometer } from '@capgo/capacitor-barometer'; await CapacitorBarometer.startMeasurementUpdates(); ``` ### `stopMeasurementUpdates` [Section titled “stopMeasurementUpdates”](#stopmeasurementupdates) Stop the continuous updates started via . ```typescript import { CapacitorBarometer } from '@capgo/capacitor-barometer'; await CapacitorBarometer.stopMeasurementUpdates(); ``` ### `checkPermissions` [Section titled “checkPermissions”](#checkpermissions) Return the current permission state for accessing barometer data. ```typescript import { CapacitorBarometer } from '@capgo/capacitor-barometer'; await CapacitorBarometer.checkPermissions(); ``` ### `requestPermissions` [Section titled “requestPermissions”](#requestpermissions) Request permission to access barometer data if required by the platform. ```typescript import { CapacitorBarometer } from '@capgo/capacitor-barometer'; await CapacitorBarometer.requestPermissions(); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `GetMeasurementResult` [Section titled “GetMeasurementResult”](#getmeasurementresult) Alias for the most recent pressure sample. ```typescript export type GetMeasurementResult = Measurement; ``` ### `IsAvailableResult` [Section titled “IsAvailableResult”](#isavailableresult) Result returned by . ```typescript export interface IsAvailableResult { /** * Indicates whether the device exposes a barometer sensor. * * @since 1.0.0 */ isAvailable: boolean; } ``` ### `PermissionStatus` [Section titled “PermissionStatus”](#permissionstatus) Permission information returned by and . ```typescript export interface PermissionStatus { /** * The permission state for accessing barometer measurements on the current platform. * * @since 1.0.0 */ barometer: BarometerPermissionState; } ``` ### `MeasurementEvent` [Section titled “MeasurementEvent”](#measurementevent) Event payload emitted when is active. ```typescript export type MeasurementEvent = Measurement; ``` ### `Measurement` [Section titled “Measurement”](#measurement) Air pressure and relative altitude values sampled from the device barometer. ```typescript export interface Measurement { /** * The static air pressure in hectopascals (hPa). * * @since 1.0.0 */ pressure: number; /** * The change in altitude relative to the time updates started. * Only available on iOS; Android will always return `0`. * * @since 1.0.0 */ relativeAltitude: number; /** * The timestamp of the measurement in milliseconds since the Unix epoch. * * @since 1.0.0 */ timestamp: number; } ``` ### `BarometerPermissionState` [Section titled “BarometerPermissionState”](#barometerpermissionstate) Permission state union including `limited` for platforms that can throttle sensor access. ```typescript export type BarometerPermissionState = PermissionState | 'limited'; ``` ### `PermissionState` [Section titled “PermissionState”](#permissionstate) Platform permission states supported by Capacitor. ```typescript export type PermissionState = 'prompt' | 'prompt-with-rationale' | 'granted' | 'denied'; ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-bluetooth-low-energy > Capacitor Bluetooth Low Energy Plugin for BLE communication. ## Overview [Section titled “Overview”](#overview) Capacitor Bluetooth Low Energy Plugin for BLE communication. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `initialize` - Initialize the BLE plugin. Must be called before any other method. * `shimWebBluetooth` - Install the Capacitor Web Bluetooth shim on `navigator.bluetooth`. Call this manually before using the Web Bluetooth API from a Capacitor native app. * `isAvailable` - Check if Bluetooth is available on the device. * `isEnabled` - Check if Bluetooth is enabled on the device. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ---------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | | `initialize` | Initialize the BLE plugin. Must be called before any other method. | | `shimWebBluetooth` | Install the Capacitor Web Bluetooth shim on `navigator.bluetooth`. Call this manually before using the Web Bluetooth API from a Capacitor native app. | | `isAvailable` | Check if Bluetooth is available on the device. | | `isEnabled` | Check if Bluetooth is enabled on the device. | | `isLocationEnabled` | Check if location services are enabled (Android only). | | `openAppSettings` | Open the app settings page. | | `openBluetoothSettings` | Open the Bluetooth settings page (Android only). | | `openLocationSettings` | Open the location settings page (Android only). | | `checkPermissions` | Check the current permission status. | | `requestPermissions` | Request Bluetooth permissions. | | `startScan` | Start scanning for BLE devices. | | `stopScan` | Stop scanning for BLE devices. | | `connect` | Connect to a BLE device. | | `disconnect` | Disconnect from a BLE device. | | `createBond` | Create a bond with a BLE device (Android only). | | `isBonded` | Check if a device is bonded (Android only). | | `discoverServices` | Discover services on a connected device. | | `getServices` | Get discovered services for a device. | | `getConnectedDevices` | Get a list of connected devices. | | `readCharacteristic` | Read a characteristic value. | | `writeCharacteristic` | Write a value to a characteristic. | | `startCharacteristicNotifications` | Start notifications for a characteristic. | | `stopCharacteristicNotifications` | Stop notifications for a characteristic. | | `readDescriptor` | Read a descriptor value. | | `writeDescriptor` | Write a value to a descriptor. | | `readRssi` | Read the RSSI (signal strength) of a connected device. | | `requestMtu` | Request MTU size change (Android only). | | `requestConnectionPriority` | Request connection priority (Android only). | | `startAdvertising` | Start advertising as a peripheral (BLE server). | | `stopAdvertising` | Stop advertising. | | `startForegroundService` | Start a foreground service to maintain BLE connections in background (Android only). | | `stopForegroundService` | Stop the foreground service (Android only). | | `getPluginVersion` | Get the native Capacitor plugin version. | | `addListener` | Add a listener for device scanned events. | | `addListener` | Add a listener for device connected events. | | `addListener` | Add a listener for device disconnected events. | | `addListener` | Add a listener for characteristic changed events. | | `removeAllListeners` | Remove all listeners for this plugin. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-bluetooth-low-energy](https://github.com/Cap-go/capacitor-bluetooth-low-energy/). # Getting Started > Install @capgo/capacitor-bluetooth-low-energy and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-bluetooth-low-energy bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { BluetoothLowEnergy } from '@capgo/capacitor-bluetooth-low-energy'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `initialize` [Section titled “initialize”](#initialize) Initialize the BLE plugin. Must be called before any other method. ```typescript import { BluetoothLowEnergy } from '@capgo/capacitor-bluetooth-low-energy'; await BluetoothLowEnergy.initialize({ mode: 'central' }); ``` ### `shimWebBluetooth` [Section titled “shimWebBluetooth”](#shimwebbluetooth) Install the Capacitor Web Bluetooth shim on `navigator.bluetooth`. Call this manually before using the Web Bluetooth API from a Capacitor native app. ```typescript import { BluetoothLowEnergy } from '@capgo/capacitor-bluetooth-low-energy'; BluetoothLowEnergy.shimWebBluetooth(); ``` ### `isAvailable` [Section titled “isAvailable”](#isavailable) Check if Bluetooth is available on the device. ```typescript import { BluetoothLowEnergy } from '@capgo/capacitor-bluetooth-low-energy'; const { available } = await BluetoothLowEnergy.isAvailable(); ``` ### `isEnabled` [Section titled “isEnabled”](#isenabled) Check if Bluetooth is enabled on the device. ```typescript import { BluetoothLowEnergy } from '@capgo/capacitor-bluetooth-low-energy'; const { enabled } = await BluetoothLowEnergy.isEnabled(); ``` ### `isLocationEnabled` [Section titled “isLocationEnabled”](#islocationenabled) Check if location services are enabled (Android only). ```typescript import { BluetoothLowEnergy } from '@capgo/capacitor-bluetooth-low-energy'; const { enabled } = await BluetoothLowEnergy.isLocationEnabled(); ``` ### `openAppSettings` [Section titled “openAppSettings”](#openappsettings) Open the app settings page. ```typescript import { BluetoothLowEnergy } from '@capgo/capacitor-bluetooth-low-energy'; await BluetoothLowEnergy.openAppSettings(); ``` ### `openBluetoothSettings` [Section titled “openBluetoothSettings”](#openbluetoothsettings) Open the Bluetooth settings page (Android only). ```typescript import { BluetoothLowEnergy } from '@capgo/capacitor-bluetooth-low-energy'; await BluetoothLowEnergy.openBluetoothSettings(); ``` ### `openLocationSettings` [Section titled “openLocationSettings”](#openlocationsettings) Open the location settings page (Android only). ```typescript import { BluetoothLowEnergy } from '@capgo/capacitor-bluetooth-low-energy'; await BluetoothLowEnergy.openLocationSettings(); ``` ### `checkPermissions` [Section titled “checkPermissions”](#checkpermissions) Check the current permission status. ```typescript import { BluetoothLowEnergy } from '@capgo/capacitor-bluetooth-low-energy'; const { bluetooth, location } = await BluetoothLowEnergy.checkPermissions(); ``` ### `requestPermissions` [Section titled “requestPermissions”](#requestpermissions) Request Bluetooth permissions. ```typescript import { BluetoothLowEnergy } from '@capgo/capacitor-bluetooth-low-energy'; const { bluetooth, location } = await BluetoothLowEnergy.requestPermissions(); ``` ### `startScan` [Section titled “startScan”](#startscan) Start scanning for BLE devices. ```typescript import { BluetoothLowEnergy } from '@capgo/capacitor-bluetooth-low-energy'; await BluetoothLowEnergy.startScan({ services: ['180D'], // Heart Rate Service timeout: 10000 }); ``` ### `stopScan` [Section titled “stopScan”](#stopscan) Stop scanning for BLE devices. ```typescript import { BluetoothLowEnergy } from '@capgo/capacitor-bluetooth-low-energy'; await BluetoothLowEnergy.stopScan(); ``` ### `connect` [Section titled “connect”](#connect) Connect to a BLE device. ```typescript import { BluetoothLowEnergy } from '@capgo/capacitor-bluetooth-low-energy'; await BluetoothLowEnergy.connect({ deviceId: 'AA:BB:CC:DD:EE:FF' }); ``` ### `disconnect` [Section titled “disconnect”](#disconnect) Disconnect from a BLE device. ```typescript import { BluetoothLowEnergy } from '@capgo/capacitor-bluetooth-low-energy'; await BluetoothLowEnergy.disconnect({ deviceId: 'AA:BB:CC:DD:EE:FF' }); ``` ### `createBond` [Section titled “createBond”](#createbond) Create a bond with a BLE device (Android only). ```typescript import { BluetoothLowEnergy } from '@capgo/capacitor-bluetooth-low-energy'; await BluetoothLowEnergy.createBond({ deviceId: 'AA:BB:CC:DD:EE:FF' }); ``` ### `isBonded` [Section titled “isBonded”](#isbonded) Check if a device is bonded (Android only). ```typescript import { BluetoothLowEnergy } from '@capgo/capacitor-bluetooth-low-energy'; const { bonded } = await BluetoothLowEnergy.isBonded({ deviceId: 'AA:BB:CC:DD:EE:FF' }); ``` ### `discoverServices` [Section titled “discoverServices”](#discoverservices) Discover services on a connected device. ```typescript import { BluetoothLowEnergy } from '@capgo/capacitor-bluetooth-low-energy'; await BluetoothLowEnergy.discoverServices({ deviceId: 'AA:BB:CC:DD:EE:FF' }); ``` ### `getServices` [Section titled “getServices”](#getservices) Get discovered services for a device. ```typescript import { BluetoothLowEnergy } from '@capgo/capacitor-bluetooth-low-energy'; const { services } = await BluetoothLowEnergy.getServices({ deviceId: 'AA:BB:CC:DD:EE:FF' }); ``` ### `getConnectedDevices` [Section titled “getConnectedDevices”](#getconnecteddevices) Get a list of connected devices. ```typescript import { BluetoothLowEnergy } from '@capgo/capacitor-bluetooth-low-energy'; const { devices } = await BluetoothLowEnergy.getConnectedDevices(); ``` ### `readCharacteristic` [Section titled “readCharacteristic”](#readcharacteristic) Read a characteristic value. ```typescript import { BluetoothLowEnergy } from '@capgo/capacitor-bluetooth-low-energy'; const { value } = await BluetoothLowEnergy.readCharacteristic({ deviceId: 'AA:BB:CC:DD:EE:FF', service: '180D', characteristic: '2A37' }); ``` ### `writeCharacteristic` [Section titled “writeCharacteristic”](#writecharacteristic) Write a value to a characteristic. ```typescript import { BluetoothLowEnergy } from '@capgo/capacitor-bluetooth-low-energy'; await BluetoothLowEnergy.writeCharacteristic({ deviceId: 'AA:BB:CC:DD:EE:FF', service: '180D', characteristic: '2A39', value: [0x01] }); ``` ### `startCharacteristicNotifications` [Section titled “startCharacteristicNotifications”](#startcharacteristicnotifications) Start notifications for a characteristic. ```typescript import { BluetoothLowEnergy } from '@capgo/capacitor-bluetooth-low-energy'; await BluetoothLowEnergy.startCharacteristicNotifications({ deviceId: 'AA:BB:CC:DD:EE:FF', service: '180D', characteristic: '2A37' }); ``` ### `stopCharacteristicNotifications` [Section titled “stopCharacteristicNotifications”](#stopcharacteristicnotifications) Stop notifications for a characteristic. ```typescript import { BluetoothLowEnergy } from '@capgo/capacitor-bluetooth-low-energy'; await BluetoothLowEnergy.stopCharacteristicNotifications({ deviceId: 'AA:BB:CC:DD:EE:FF', service: '180D', characteristic: '2A37' }); ``` ### `readDescriptor` [Section titled “readDescriptor”](#readdescriptor) Read a descriptor value. ```typescript import { BluetoothLowEnergy } from '@capgo/capacitor-bluetooth-low-energy'; const { value } = await BluetoothLowEnergy.readDescriptor({ deviceId: 'AA:BB:CC:DD:EE:FF', service: '180D', characteristic: '2A37', descriptor: '2902' }); ``` ### `writeDescriptor` [Section titled “writeDescriptor”](#writedescriptor) Write a value to a descriptor. ```typescript import { BluetoothLowEnergy } from '@capgo/capacitor-bluetooth-low-energy'; await BluetoothLowEnergy.writeDescriptor({ deviceId: 'AA:BB:CC:DD:EE:FF', service: '180D', characteristic: '2A37', descriptor: '2902', value: [0x01, 0x00] }); ``` ### `readRssi` [Section titled “readRssi”](#readrssi) Read the RSSI (signal strength) of a connected device. ```typescript import { BluetoothLowEnergy } from '@capgo/capacitor-bluetooth-low-energy'; const { rssi } = await BluetoothLowEnergy.readRssi({ deviceId: 'AA:BB:CC:DD:EE:FF' }); ``` ### `requestMtu` [Section titled “requestMtu”](#requestmtu) Request MTU size change (Android only). ```typescript import { BluetoothLowEnergy } from '@capgo/capacitor-bluetooth-low-energy'; const { mtu } = await BluetoothLowEnergy.requestMtu({ deviceId: 'AA:BB:CC:DD:EE:FF', mtu: 512 }); ``` ### `requestConnectionPriority` [Section titled “requestConnectionPriority”](#requestconnectionpriority) Request connection priority (Android only). ```typescript import { BluetoothLowEnergy } from '@capgo/capacitor-bluetooth-low-energy'; await BluetoothLowEnergy.requestConnectionPriority({ deviceId: 'AA:BB:CC:DD:EE:FF', priority: 'high' }); ``` ### `startAdvertising` [Section titled “startAdvertising”](#startadvertising) Start advertising as a peripheral (BLE server). ```typescript import { BluetoothLowEnergy } from '@capgo/capacitor-bluetooth-low-energy'; await BluetoothLowEnergy.startAdvertising({ name: 'MyDevice', services: ['180D'] }); ``` ### `stopAdvertising` [Section titled “stopAdvertising”](#stopadvertising) Stop advertising. ```typescript import { BluetoothLowEnergy } from '@capgo/capacitor-bluetooth-low-energy'; await BluetoothLowEnergy.stopAdvertising(); ``` ### `startForegroundService` [Section titled “startForegroundService”](#startforegroundservice) Start a foreground service to maintain BLE connections in background (Android only). ```typescript import { BluetoothLowEnergy } from '@capgo/capacitor-bluetooth-low-energy'; await BluetoothLowEnergy.startForegroundService({ title: 'BLE Connection', body: 'Maintaining connection...' }); ``` ### `stopForegroundService` [Section titled “stopForegroundService”](#stopforegroundservice) Stop the foreground service (Android only). ```typescript import { BluetoothLowEnergy } from '@capgo/capacitor-bluetooth-low-energy'; await BluetoothLowEnergy.stopForegroundService(); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `InitializeOptions` [Section titled “InitializeOptions”](#initializeoptions) Initialization options for the plugin. ```typescript export interface InitializeOptions { /** * The mode to initialize the plugin in. * - 'central': Act as a BLE central (client) * - 'peripheral': Act as a BLE peripheral (server) * * @default 'central' * @since 1.0.0 */ mode?: 'central' | 'peripheral'; } ``` ### `IsAvailableResult` [Section titled “IsAvailableResult”](#isavailableresult) Result of the isAvailable method. ```typescript export interface IsAvailableResult { /** * Whether Bluetooth is available on the device. * * @since 1.0.0 */ available: boolean; } ``` ### `IsEnabledResult` [Section titled “IsEnabledResult”](#isenabledresult) Result of the isEnabled method. ```typescript export interface IsEnabledResult { /** * Whether Bluetooth is enabled on the device. * * @since 1.0.0 */ enabled: boolean; } ``` ### `IsLocationEnabledResult` [Section titled “IsLocationEnabledResult”](#islocationenabledresult) Result of the isLocationEnabled method. ```typescript export interface IsLocationEnabledResult { /** * Whether location services are enabled on the device. * * @since 1.0.0 */ enabled: boolean; } ``` ### `PermissionStatus` [Section titled “PermissionStatus”](#permissionstatus) Permission status for Bluetooth and location. ```typescript export interface PermissionStatus { /** * Bluetooth permission status. * * @since 1.0.0 */ bluetooth: PermissionState; /** * Location permission status (Android only). * * @since 1.0.0 */ location: PermissionState; } ``` ### `StartScanOptions` [Section titled “StartScanOptions”](#startscanoptions) Options for starting a scan. ```typescript export interface StartScanOptions { /** * List of service UUIDs to filter by. * Only devices advertising these services will be returned. * * @since 1.0.0 */ services?: string[]; /** * Scan timeout in milliseconds. * Set to 0 for no timeout. * * @default 0 * @since 1.0.0 */ timeout?: number; /** * Whether to allow duplicate scan results. * * @default false * @since 1.0.0 */ allowDuplicates?: boolean; } ``` ### `ConnectOptions` [Section titled “ConnectOptions”](#connectoptions) Options for connecting to a device. ```typescript export interface ConnectOptions { /** * The device ID (MAC address on Android, UUID on iOS). * * @since 1.0.0 */ deviceId: string; /** * Whether to automatically connect when the device becomes available. * * @default false * @since 1.0.0 */ autoConnect?: boolean; } ``` ### `DisconnectOptions` [Section titled “DisconnectOptions”](#disconnectoptions) Options for disconnecting from a device. ```typescript export interface DisconnectOptions { /** * The device ID to disconnect from. * * @since 1.0.0 */ deviceId: string; } ``` ### `CreateBondOptions` [Section titled “CreateBondOptions”](#createbondoptions) Options for creating a bond. ```typescript export interface CreateBondOptions { /** * The device ID to bond with. * * @since 1.0.0 */ deviceId: string; } ``` ### `IsBondedOptions` [Section titled “IsBondedOptions”](#isbondedoptions) Options for checking bond status. ```typescript export interface IsBondedOptions { /** * The device ID to check. * * @since 1.0.0 */ deviceId: string; } ``` ### `IsBondedResult` [Section titled “IsBondedResult”](#isbondedresult) Result of the isBonded method. ```typescript export interface IsBondedResult { /** * Whether the device is bonded. * * @since 1.0.0 */ bonded: boolean; } ``` ### `DiscoverServicesOptions` [Section titled “DiscoverServicesOptions”](#discoverservicesoptions) Options for discovering services. ```typescript export interface DiscoverServicesOptions { /** * The device ID to discover services on. * * @since 1.0.0 */ deviceId: string; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-brightness > Control screen brightness on iOS and Android. ## Overview [Section titled “Overview”](#overview) Control screen brightness on iOS and Android. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `getBrightness` - Get the current brightness level of the device’s main screen. * `setBrightness` - Set the brightness level of the device’s main screen. * `getSystemBrightness` - Get the system-wide screen brightness. * `setSystemBrightness` - Set the system-wide screen brightness. Requires WRITE\_SETTINGS permission on Android. This also changes the brightness mode to MANUAL. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | | `getBrightness` | Get the current brightness level of the device’s main screen. | | `setBrightness` | Set the brightness level of the device’s main screen. | | `getSystemBrightness` | Get the system-wide screen brightness. | | `setSystemBrightness` | Set the system-wide screen brightness. Requires WRITE\_SETTINGS permission on Android. This also changes the brightness mode to MANUAL. | | `getSystemBrightnessMode` | Get the current system brightness mode (automatic or manual). Requires WRITE\_SETTINGS permission on Android. | | `setSystemBrightnessMode` | Set the system brightness mode (automatic or manual). Requires WRITE\_SETTINGS permission on Android. | | `isUsingSystemBrightness` | Check if the current activity is using the system-wide brightness value. | | `restoreSystemBrightness` | Reset the brightness setting of the current activity to use the system-wide value. | | `isAvailable` | Check if the Brightness API is available on the current device. | | `checkPermissions` | Check user’s permissions for accessing system brightness. | | `requestPermissions` | Request permissions for accessing system brightness. On Android, this opens the system settings to grant WRITE\_SETTINGS permission. | | `getPluginVersion` | Get the native plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-brightness](https://github.com/Cap-go/capacitor-brightness/). # Getting Started > Install @capgo/capacitor-brightness and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-brightness bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { CapgoBrightness } from '@capgo/capacitor-brightness'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `getBrightness` [Section titled “getBrightness”](#getbrightness) Get the current brightness level of the device’s main screen. ```typescript import { CapgoBrightness } from '@capgo/capacitor-brightness'; await CapgoBrightness.getBrightness(); ``` ### `setBrightness` [Section titled “setBrightness”](#setbrightness) Set the brightness level of the device’s main screen. On iOS, the brightness will persist until the device is locked. On Android, the brightness only applies to the current activity. ```typescript import { CapgoBrightness } from '@capgo/capacitor-brightness'; await CapgoBrightness.setBrightness({} as SetBrightnessOptions); ``` ### `getSystemBrightness` [Section titled “getSystemBrightness”](#getsystembrightness) Get the system-wide screen brightness. ```typescript import { CapgoBrightness } from '@capgo/capacitor-brightness'; await CapgoBrightness.getSystemBrightness(); ``` ### `setSystemBrightness` [Section titled “setSystemBrightness”](#setsystembrightness) Set the system-wide screen brightness. Requires WRITE\_SETTINGS permission on Android. This also changes the brightness mode to MANUAL. ```typescript import { CapgoBrightness } from '@capgo/capacitor-brightness'; await CapgoBrightness.setSystemBrightness({} as SetBrightnessOptions); ``` ### `getSystemBrightnessMode` [Section titled “getSystemBrightnessMode”](#getsystembrightnessmode) Get the current system brightness mode (automatic or manual). Requires WRITE\_SETTINGS permission on Android. ```typescript import { CapgoBrightness } from '@capgo/capacitor-brightness'; await CapgoBrightness.getSystemBrightnessMode(); ``` ### `setSystemBrightnessMode` [Section titled “setSystemBrightnessMode”](#setsystembrightnessmode) Set the system brightness mode (automatic or manual). Requires WRITE\_SETTINGS permission on Android. ```typescript import { CapgoBrightness } from '@capgo/capacitor-brightness'; await CapgoBrightness.setSystemBrightnessMode({} as SetBrightnessModeOptions); ``` ### `isUsingSystemBrightness` [Section titled “isUsingSystemBrightness”](#isusingsystembrightness) Check if the current activity is using the system-wide brightness value. ```typescript import { CapgoBrightness } from '@capgo/capacitor-brightness'; await CapgoBrightness.isUsingSystemBrightness(); ``` ### `restoreSystemBrightness` [Section titled “restoreSystemBrightness”](#restoresystembrightness) Reset the brightness setting of the current activity to use the system-wide value. ```typescript import { CapgoBrightness } from '@capgo/capacitor-brightness'; await CapgoBrightness.restoreSystemBrightness(); ``` ### `isAvailable` [Section titled “isAvailable”](#isavailable) Check if the Brightness API is available on the current device. ```typescript import { CapgoBrightness } from '@capgo/capacitor-brightness'; await CapgoBrightness.isAvailable(); ``` ### `checkPermissions` [Section titled “checkPermissions”](#checkpermissions) Check user’s permissions for accessing system brightness. ```typescript import { CapgoBrightness } from '@capgo/capacitor-brightness'; await CapgoBrightness.checkPermissions(); ``` ### `requestPermissions` [Section titled “requestPermissions”](#requestpermissions) Request permissions for accessing system brightness. On Android, this opens the system settings to grant WRITE\_SETTINGS permission. ```typescript import { CapgoBrightness } from '@capgo/capacitor-brightness'; await CapgoBrightness.requestPermissions(); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `GetBrightnessResult` [Section titled “GetBrightnessResult”](#getbrightnessresult) Result of getBrightness or getSystemBrightness. ```typescript export interface GetBrightnessResult { /** * The brightness value from 0 to 1. * 0 is the minimum brightness, 1 is the maximum brightness. * * @since 8.0.0 */ brightness: number; } ``` ### `SetBrightnessOptions` [Section titled “SetBrightnessOptions”](#setbrightnessoptions) Options for setBrightness or setSystemBrightness. ```typescript export interface SetBrightnessOptions { /** * The brightness value from 0 to 1. * 0 is the minimum brightness, 1 is the maximum brightness. * * @since 8.0.0 */ brightness: number; } ``` ### `GetBrightnessModeResult` [Section titled “GetBrightnessModeResult”](#getbrightnessmoderesult) Result of getSystemBrightnessMode. ```typescript export interface GetBrightnessModeResult { /** * The current brightness mode. * * @since 8.0.0 */ mode: BrightnessMode; } ``` ### `SetBrightnessModeOptions` [Section titled “SetBrightnessModeOptions”](#setbrightnessmodeoptions) Options for setSystemBrightnessMode. ```typescript export interface SetBrightnessModeOptions { /** * The brightness mode to set. * Cannot be set to UNKNOWN. * * @since 8.0.0 */ mode: BrightnessMode; } ``` ### `IsUsingSystemBrightnessResult` [Section titled “IsUsingSystemBrightnessResult”](#isusingsystembrightnessresult) Result of isUsingSystemBrightness. ```typescript export interface IsUsingSystemBrightnessResult { /** * Whether the current activity is using the system-wide brightness value. * * @since 8.0.0 */ isUsing: boolean; } ``` ### `IsAvailableResult` [Section titled “IsAvailableResult”](#isavailableresult) Result of isAvailable. ```typescript export interface IsAvailableResult { /** * Whether the Brightness API is available on the current device. * * @since 8.0.0 */ available: boolean; } ``` ### `PermissionStatus` [Section titled “PermissionStatus”](#permissionstatus) Permission status result. ```typescript export interface PermissionStatus { /** * Whether the permission to modify system brightness is granted. * * @since 8.0.0 */ brightness: PermissionState; } ``` ### `GetPluginVersionResult` [Section titled “GetPluginVersionResult”](#getpluginversionresult) Result of getPluginVersion. ```typescript export interface GetPluginVersionResult { /** * The native plugin version. * * @since 8.0.0 */ version: string; } ``` ### `BrightnessMode` [Section titled “BrightnessMode”](#brightnessmode) The brightness mode. ```typescript export enum BrightnessMode { /** * The brightness mode is unknown. * * @since 8.0.0 */ UNKNOWN = 0, /** * The brightness is automatically adjusted by the system. * * @since 8.0.0 */ AUTOMATIC = 1, /** * The brightness is manually set by the user. * * @since 8.0.0 */ MANUAL = 2, } ``` ### `PermissionState` [Section titled “PermissionState”](#permissionstate) Permission state. ```typescript export type PermissionState = 'prompt' | 'prompt-with-rationale' | 'granted' | 'denied'; ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/camera-preview > The main interface for the CameraPreview plugin. ## Overview [Section titled “Overview”](#overview) The main interface for the CameraPreview plugin. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `start` - Starts the camera preview. * `stop` - Stops the camera preview. * `capture` - Captures a picture from the camera. * `captureSample` - Captures a single frame from the camera preview stream. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `start` | Starts the camera preview. | | `stop` | Stops the camera preview. | | `capture` | Captures a picture from the camera. | | `captureSample` | Captures a single frame from the camera preview stream. | | `getSupportedFlashModes` | Gets the flash modes supported by the active camera. | | `setAspectRatio` | Set the aspect ratio of the camera preview. | | `getAspectRatio` | Gets the current aspect ratio of the camera preview. | | `setGridMode` | Sets the grid mode of the camera preview overlay. | | `getGridMode` | Gets the current grid mode of the camera preview overlay. | | `checkPermissions` | Checks the current camera (and optionally microphone) permission status without prompting the system dialog. | | `requestPermissions` | Requests camera (and optional microphone) permissions. If permissions are already granted or denied, the current status is returned without prompting. When `showSettingsAlert` is true and permissions are denied, a platform-specific alert guiding the user to the app settings will be presented. | | `getHorizontalFov` | Gets the horizontal field of view for the active camera. Note: This can be an estimate on some devices. | | `getSupportedPictureSizes` | Gets the supported picture sizes for all cameras. | | `setFlashMode` | Sets the flash mode for the active camera. | | `flip` | Toggles between the front and rear cameras. | | `setOpacity` | Sets the opacity of the camera preview. | | `stopRecordVideo` | Stops an ongoing video recording. | | `startRecordVideo` | Starts recording a video. | | `isRunning` | Checks if the camera preview is currently running. | | `getAvailableDevices` | Gets all available camera devices. | | `getZoom` | Gets the current zoom state, including min/max and current lens info. | | `getZoomButtonValues` | Returns zoom button values for quick switching. - iOS/Android: includes 0.5 if ultra-wide available; 1 and 2 if wide available; 3 if telephoto available - Web: unsupported. | | `setZoom` | Sets the zoom level of the camera. | | `getFlashMode` | Gets the current flash mode. | | `removeAllListeners` | Removes all registered listeners. | | `setDeviceId` | Switches the active camera to the one with the specified `deviceId`. | | `getDeviceId` | Gets the ID of the camera device that is currently bound. On Android, if a physical-lens request falls back to a logical camera, this returns the bound logical camera ID. | | `getPreviewSize` | Gets the current preview size and position. | | `setPreviewSize` | Sets the preview size and position. | | `setFocus` | Sets the camera focus to a specific point in the preview. | | `addListener` | Adds a listener for screen resize events. | | `addListener` | Adds a listener for orientation change events. | | `deleteFile` | Deletes a file at the given absolute path on the device. Use this to quickly clean up temporary images created with `storeToFile`. On web, this is not supported and will throw. | | `getSafeAreaInsets` | Gets the safe area insets for devices. Returns the orientation-aware notch/camera cutout inset and the current orientation. In portrait mode: returns top inset (notch at top). In landscape mode: returns left inset (notch moved to side). This specifically targets the cutout area (notch, punch hole, etc.) that all modern phones have. | | `getOrientation` | Gets the current device orientation in a cross-platform format. | | `getExposureModes` | Returns the exposure modes supported by the active camera. Modes can include: ‘locked’, ‘auto’, ‘continuous’, ‘custom’. | | `getExposureMode` | Returns the current exposure mode. | | `setExposureMode` | Sets the exposure mode. | | `getExposureCompensationRange` | Returns the exposure compensation (EV bias) supported range. | | `getExposureCompensation` | Returns the current exposure compensation (EV bias). | | `setExposureCompensation` | Sets the exposure compensation (EV bias). Value will be clamped to range. | | `getPluginVersion` | Get the native Capacitor plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-camera-preview](https://github.com/Cap-go/capacitor-camera-preview/). # Getting Started > Install @capgo/camera-preview and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/camera-preview bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { CameraPreview } from '@capgo/camera-preview'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `start` [Section titled “start”](#start) Starts the camera preview. ```typescript import { CameraPreview } from '@capgo/camera-preview'; await CameraPreview.start({} as CameraPreviewOptions); ``` ### `stop` [Section titled “stop”](#stop) Stops the camera preview. ```typescript import { CameraPreview } from '@capgo/camera-preview'; await CameraPreview.stop(); ``` ### `capture` [Section titled “capture”](#capture) Captures a picture from the camera. If `storeToFile` was set to `true` when starting the preview, the returned `value` will be an absolute file path on the device instead of a base64 string. Use getBase64FromFilePath to get the base64 string from the file path. ```typescript import { CameraPreview } from '@capgo/camera-preview'; await CameraPreview.capture({} as CameraPreviewPictureOptions); ``` ### `captureSample` [Section titled “captureSample”](#capturesample) Captures a single frame from the camera preview stream. ```typescript import { CameraPreview } from '@capgo/camera-preview'; await CameraPreview.captureSample({} as CameraSampleOptions); ``` ### `getSupportedFlashModes` [Section titled “getSupportedFlashModes”](#getsupportedflashmodes) Gets the flash modes supported by the active camera. ```typescript import { CameraPreview } from '@capgo/camera-preview'; await CameraPreview.getSupportedFlashModes(); ``` ### `setAspectRatio` [Section titled “setAspectRatio”](#setaspectratio) Set the aspect ratio of the camera preview. ```typescript import { CameraPreview } from '@capgo/camera-preview'; await CameraPreview.setAspectRatio({} as { aspectRatio: '4:3' | '16:9'; x?: number; y?: number }); ``` ### `getAspectRatio` [Section titled “getAspectRatio”](#getaspectratio) Gets the current aspect ratio of the camera preview. ```typescript import { CameraPreview } from '@capgo/camera-preview'; await CameraPreview.getAspectRatio(); ``` ### `setGridMode` [Section titled “setGridMode”](#setgridmode) Sets the grid mode of the camera preview overlay. ```typescript import { CameraPreview } from '@capgo/camera-preview'; await CameraPreview.setGridMode({} as { gridMode: GridMode }); ``` ### `getGridMode` [Section titled “getGridMode”](#getgridmode) Gets the current grid mode of the camera preview overlay. ```typescript import { CameraPreview } from '@capgo/camera-preview'; await CameraPreview.getGridMode(); ``` ### `checkPermissions` [Section titled “checkPermissions”](#checkpermissions) Checks the current camera (and optionally microphone) permission status without prompting the system dialog. ```typescript import { CameraPreview } from '@capgo/camera-preview'; await CameraPreview.checkPermissions(); ``` ### `requestPermissions` [Section titled “requestPermissions”](#requestpermissions) Requests camera (and optional microphone) permissions. If permissions are already granted or denied, the current status is returned without prompting. When `showSettingsAlert` is true and permissions are denied, a platform-specific alert guiding the user to the app settings will be presented. ```typescript import { CameraPreview } from '@capgo/camera-preview'; await CameraPreview.requestPermissions(); ``` ### `getHorizontalFov` [Section titled “getHorizontalFov”](#gethorizontalfov) Gets the horizontal field of view for the active camera. Note: This can be an estimate on some devices. ```typescript import { CameraPreview } from '@capgo/camera-preview'; await CameraPreview.getHorizontalFov(); ``` ### `getSupportedPictureSizes` [Section titled “getSupportedPictureSizes”](#getsupportedpicturesizes) Gets the supported picture sizes for all cameras. ```typescript import { CameraPreview } from '@capgo/camera-preview'; await CameraPreview.getSupportedPictureSizes(); ``` ### `setFlashMode` [Section titled “setFlashMode”](#setflashmode) Sets the flash mode for the active camera. ```typescript import { CameraPreview } from '@capgo/camera-preview'; await CameraPreview.setFlashMode({} as { flashMode: CameraPreviewFlashMode | string }); ``` ### `flip` [Section titled “flip”](#flip) Toggles between the front and rear cameras. ```typescript import { CameraPreview } from '@capgo/camera-preview'; await CameraPreview.flip(); ``` ### `setOpacity` [Section titled “setOpacity”](#setopacity) Sets the opacity of the camera preview. ```typescript import { CameraPreview } from '@capgo/camera-preview'; await CameraPreview.setOpacity({} as CameraOpacityOptions); ``` ### `stopRecordVideo` [Section titled “stopRecordVideo”](#stoprecordvideo) Stops an ongoing video recording. ```typescript import { CameraPreview } from '@capgo/camera-preview'; await CameraPreview.stopRecordVideo(); ``` ### `startRecordVideo` [Section titled “startRecordVideo”](#startrecordvideo) Starts recording a video. ```typescript import { CameraPreview } from '@capgo/camera-preview'; await CameraPreview.startRecordVideo({} as CameraPreviewOptions); ``` ### `isRunning` [Section titled “isRunning”](#isrunning) Checks if the camera preview is currently running. ```typescript import { CameraPreview } from '@capgo/camera-preview'; await CameraPreview.isRunning(); ``` ### `getAvailableDevices` [Section titled “getAvailableDevices”](#getavailabledevices) Gets all available camera devices. ```typescript import { CameraPreview } from '@capgo/camera-preview'; await CameraPreview.getAvailableDevices(); ``` ### `getZoom` [Section titled “getZoom”](#getzoom) Gets the current zoom state, including min/max and current lens info. ```typescript import { CameraPreview } from '@capgo/camera-preview'; await CameraPreview.getZoom(); ``` ### `getZoomButtonValues` [Section titled “getZoomButtonValues”](#getzoombuttonvalues) Returns zoom button values for quick switching. * iOS/Android: includes 0.5 if ultra-wide available; 1 and 2 if wide available; 3 if telephoto available * Web: unsupported ```typescript import { CameraPreview } from '@capgo/camera-preview'; await CameraPreview.getZoomButtonValues(); ``` ### `setZoom` [Section titled “setZoom”](#setzoom) Sets the zoom level of the camera. ```typescript import { CameraPreview } from '@capgo/camera-preview'; await CameraPreview.setZoom({} as { level: number; ramp?: boolean; autoFocus?: boolean }); ``` ### `getFlashMode` [Section titled “getFlashMode”](#getflashmode) Gets the current flash mode. ```typescript import { CameraPreview } from '@capgo/camera-preview'; await CameraPreview.getFlashMode(); ``` ### `setDeviceId` [Section titled “setDeviceId”](#setdeviceid) Switches the active camera to the one with the specified `deviceId`. ```typescript import { CameraPreview } from '@capgo/camera-preview'; await CameraPreview.setDeviceId({} as { deviceId: string }); ``` ### `getDeviceId` [Section titled “getDeviceId”](#getdeviceid) Gets the ID of the camera device that is currently bound. On Android, if a physical-lens request falls back to a logical camera, this returns the bound logical camera ID. ```typescript import { CameraPreview } from '@capgo/camera-preview'; await CameraPreview.getDeviceId(); ``` ### `getPreviewSize` [Section titled “getPreviewSize”](#getpreviewsize) Gets the current preview size and position. ```typescript import { CameraPreview } from '@capgo/camera-preview'; await CameraPreview.getPreviewSize(); ``` ### `setPreviewSize` [Section titled “setPreviewSize”](#setpreviewsize) Sets the preview size and position. ```typescript import { CameraPreview } from '@capgo/camera-preview'; await CameraPreview.setPreviewSize({} as { x?: number; y?: number; width: number; height: number }); ``` ### `setFocus` [Section titled “setFocus”](#setfocus) Sets the camera focus to a specific point in the preview. Note: The plugin does not attach any native tap-to-focus gesture handlers. Handle taps in your HTML/JS (e.g., on the overlaying UI), then pass normalized coordinates here. ```typescript import { CameraPreview } from '@capgo/camera-preview'; await CameraPreview.setFocus({} as { x: number; y: number }); ``` ### `deleteFile` [Section titled “deleteFile”](#deletefile) Deletes a file at the given absolute path on the device. Use this to quickly clean up temporary images created with `storeToFile`. On web, this is not supported and will throw. ```typescript import { CameraPreview } from '@capgo/camera-preview'; await CameraPreview.deleteFile({} as { path: string }); ``` ### `getSafeAreaInsets` [Section titled “getSafeAreaInsets”](#getsafeareainsets) Gets the safe area insets for devices. Returns the orientation-aware notch/camera cutout inset and the current orientation. In portrait mode: returns top inset (notch at top). In landscape mode: returns left inset (notch moved to side). This specifically targets the cutout area (notch, punch hole, etc.) that all modern phones have. Android: Values returned in dp (logical pixels). iOS: Values returned in physical pixels, excluding status bar (only pure notch/cutout size). ```typescript import { CameraPreview } from '@capgo/camera-preview'; await CameraPreview.getSafeAreaInsets(); ``` ### `getOrientation` [Section titled “getOrientation”](#getorientation) Gets the current device orientation in a cross-platform format. ```typescript import { CameraPreview } from '@capgo/camera-preview'; await CameraPreview.getOrientation(); ``` ### `getExposureModes` [Section titled “getExposureModes”](#getexposuremodes) Returns the exposure modes supported by the active camera. Modes can include: ‘locked’, ‘auto’, ‘continuous’, ‘custom’. ```typescript import { CameraPreview } from '@capgo/camera-preview'; await CameraPreview.getExposureModes(); ``` ### `getExposureMode` [Section titled “getExposureMode”](#getexposuremode) Returns the current exposure mode. ```typescript import { CameraPreview } from '@capgo/camera-preview'; await CameraPreview.getExposureMode(); ``` ### `setExposureMode` [Section titled “setExposureMode”](#setexposuremode) Sets the exposure mode. ```typescript import { CameraPreview } from '@capgo/camera-preview'; await CameraPreview.setExposureMode({} as { mode: ExposureMode }); ``` ### `getExposureCompensationRange` [Section titled “getExposureCompensationRange”](#getexposurecompensationrange) Returns the exposure compensation (EV bias) supported range. ```typescript import { CameraPreview } from '@capgo/camera-preview'; await CameraPreview.getExposureCompensationRange(); ``` ### `getExposureCompensation` [Section titled “getExposureCompensation”](#getexposurecompensation) Returns the current exposure compensation (EV bias). ```typescript import { CameraPreview } from '@capgo/camera-preview'; await CameraPreview.getExposureCompensation(); ``` ### `setExposureCompensation` [Section titled “setExposureCompensation”](#setexposurecompensation) Sets the exposure compensation (EV bias). Value will be clamped to range. ```typescript import { CameraPreview } from '@capgo/camera-preview'; await CameraPreview.setExposureCompensation({} as { value: number }); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `CameraPreviewOptions` [Section titled “CameraPreviewOptions”](#camerapreviewoptions) Defines the configuration options for starting the camera preview. ```typescript export interface CameraPreviewOptions { /** * The parent element to attach the video preview to. * @platform web */ parent?: string; /** * A CSS class name to add to the preview element. * @platform web */ className?: string; /** * The width of the preview in pixels. Defaults to the screen width. * @platform android, ios, web */ width?: number; /** * The height of the preview in pixels. Defaults to the screen height. * @platform android, ios, web */ height?: number; /** * The horizontal origin of the preview, in pixels. * @platform android, ios */ x?: number; /** * The vertical origin of the preview, in pixels. * @platform android, ios */ y?: number; /** * The aspect ratio of the camera preview, '4:3' or '16:9' or 'fill'. * Cannot be set if width or height is provided, otherwise the call will be rejected. * Use setPreviewSize to adjust size after starting. * * @since 2.0.0 */ aspectRatio?: '4:3' | '16:9'; /** * Controls how the camera preview fills the available space. * - 'contain': Fits the entire preview within the space, may show letterboxing (default). * - 'cover': Fills the entire space, may crop edges of the preview. * @default "contain" * @platform android, ios, web */ aspectMode?: 'cover' | 'contain'; /** * The grid overlay to display on the camera preview. * @default "none" * @since 2.1.0 */ gridMode?: GridMode; /** * Adjusts the y-position to account for safe areas (e.g., notches). * @platform ios * @default false */ includeSafeAreaInsets?: boolean; /** * If true, places the preview behind the webview. * @platform android * @default true */ toBack?: boolean; /** * Bottom padding for the preview, in pixels. * @platform android, ios */ paddingBottom?: number; /** * Whether to rotate the preview when the device orientation changes. * @platform ios * @default true */ rotateWhenOrientationChanged?: boolean; /** * The camera to use. * @default "rear" */ position?: CameraPosition | string; /** * If true, saves the captured image to a file and returns the file path. * If false, returns a base64 encoded string. * @default false */ storeToFile?: boolean; /** * If true, prevents the plugin from rotating the image based on EXIF data. * @platform android * @default false */ disableExifHeaderStripping?: boolean; /** * If true, disables the audio stream, preventing audio permission requests. * @default true */ disableAudio?: boolean; /** * If true, locks the device orientation while the camera is active. * @platform android * @default false */ lockAndroidOrientation?: boolean; /** * If true, allows the camera preview's opacity to be changed. * @platform android, web * @default false */ enableOpacity?: boolean; /** * If true, disables the visual focus indicator when tapping to focus. * @platform android, ios * @default false */ disableFocusIndicator?: boolean; /** * The `deviceId` of the camera to use. If provided, `position` is ignored. * @platform ios */ deviceId?: string; /** * On Android, attempts to bind a physical camera directly when `deviceId` refers to a physical lens. * Disabled by default because OEM support is inconsistent; when false, Android keeps the current logical-camera fallback behavior. * @default false * @platform android */ enablePhysicalDeviceSelection?: boolean; /** * The initial zoom level when starting the camera preview. * If the requested zoom level is not available, the native plugin will reject. * @default 1.0 * @platform android, ios * @since 2.2.0 */ initialZoomLevel?: number; /** * The vertical positioning of the camera preview. * @default "center" * @platform android, ios, web * @since 2.3.0 */ positioning?: CameraPositioning; /** * If true, enables video capture capabilities when the camera starts. * @default false * @platform android * @since 7.11.0 */ enableVideoMode?: boolean; /** * If true, forces the camera to start/restart even if it's already running or busy. * This will kill the current camera session and start a new one, ignoring all state checks. * @default false * @platform android, ios, web */ force?: boolean; /** * Sets the quality of video for recording. * Options: 'low', 'medium', 'high' * @note On Android requires 'enableVideoMode' to be true * @note Will affect the entire preview stream for iOS * @platform ios, android * @default "high" */ videoQuality?: 'low' | 'medium' | 'high'; } ``` ### `CameraPreviewPictureOptions` [Section titled “CameraPreviewPictureOptions”](#camerapreviewpictureoptions) Defines the options for capturing a picture. ```typescript export interface CameraPreviewPictureOptions { /** * The maximum height of the picture in pixels. The image will be resized to fit within this height while maintaining aspect ratio. * If not specified the captured image will match the preview's visible area. */ height?: number; /** * The maximum width of the picture in pixels. The image will be resized to fit within this width while maintaining aspect ratio. * If not specified the captured image will match the preview's visible area. */ width?: number; /** * The quality of the captured image, from 0 to 100. * Does not apply to `.png` format. * @default 85 */ quality?: number; /** * The format of the captured image. * @default "jpeg" */ format?: PictureFormat; /** * If true, the captured image will be saved to the user's gallery. * @default false * @since 7.5.0 */ saveToGallery?: boolean; /** * If true, the plugin will attempt to add GPS location data to the image's EXIF metadata. * This may prompt the user for location permissions. * @default false * @since 7.6.0 */ withExifLocation?: boolean; /** * If true, the plugin will embed a timestamp in the top-right corner of the image. * @default false * @since 7.17.0 */ embedTimestamp?: boolean; /** * If true, the plugin will embed the current location in the top-right corner of the image. * Requires `withExifLocation` to be enabled. * @default false * @since 7.18.0 */ embedLocation?: boolean; /** * Sets the priority for photo quality vs. capture speed. * - "speed": Prioritizes faster capture times, may reduce image quality. * - "balanced": Aims for a balance between quality and speed. * - "quality": Prioritizes image quality, may reduce capture speed. * See https://developer.apple.com/documentation/avfoundation/avcapturephotosettings/photoqualityprioritization for details. * * @since 7.21.0 * @platform ios * @default "speed" */ photoQualityPrioritization?: 'speed' | 'balanced' | 'quality'; } ``` ### `ExifData` [Section titled “ExifData”](#exifdata) Represents EXIF data extracted from an image. ```typescript export interface ExifData { [key: string]: any; } ``` ### `CameraSampleOptions` [Section titled “CameraSampleOptions”](#camerasampleoptions) Defines the options for capturing a sample frame from the camera preview. ```typescript export interface CameraSampleOptions { /** * The quality of the captured sample, from 0 to 100. * @default 85 */ quality?: number; } ``` ### `CameraPreviewFlashMode` [Section titled “CameraPreviewFlashMode”](#camerapreviewflashmode) The available flash modes for the camera. ‘torch’ is a continuous light mode. ```typescript export type CameraPreviewFlashMode = 'off' | 'on' | 'auto' | 'torch'; ``` ### `GridMode` [Section titled “GridMode”](#gridmode) ```typescript export type GridMode = 'none' | '3x3' | '4x4'; ``` ### `PermissionRequestOptions` [Section titled “PermissionRequestOptions”](#permissionrequestoptions) ```typescript export interface PermissionRequestOptions { disableAudio?: boolean; showSettingsAlert?: boolean; title?: string; message?: string; openSettingsButtonTitle?: string; cancelButtonTitle?: string; } ``` ### `CameraPermissionStatus` [Section titled “CameraPermissionStatus”](#camerapermissionstatus) ```typescript export interface CameraPermissionStatus { camera: PermissionState; microphone?: PermissionState; } ``` ### `SupportedPictureSizes` [Section titled “SupportedPictureSizes”](#supportedpicturesizes) Represents the supported picture sizes for a camera facing a certain direction. ```typescript export interface SupportedPictureSizes { /** The camera direction ("front" or "rear"). */ facing: string; /** A list of supported picture sizes for this camera. */ supportedPictureSizes: PictureSize[]; } ``` ### `CameraOpacityOptions` [Section titled “CameraOpacityOptions”](#cameraopacityoptions) Defines the options for setting the camera preview’s opacity. ```typescript export interface CameraOpacityOptions { /** * The opacity percentage, from 0.0 (fully transparent) to 1.0 (fully opaque). * @default 1.0 */ opacity?: number; } ``` ### `CameraDevice` [Section titled “CameraDevice”](#cameradevice) Represents a physical camera on the device (e.g., the front-facing camera). ```typescript export interface CameraDevice { /** A unique identifier for the camera device. */ deviceId: string; /** A human-readable name for the camera device. */ label: string; /** The physical position of the camera on the device. */ position: CameraPosition; /** A list of all available lenses for this camera device. */ lenses: CameraLens[]; /** The overall minimum zoom factor available across all lenses on this device. */ minZoom: number; /** The overall maximum zoom factor available across all lenses on this device. */ maxZoom: number; /** Identifies whether the device is a logical camera (composed of multiple physical lenses). */ isLogical: boolean; } ``` ### `LensInfo` [Section titled “LensInfo”](#lensinfo) Represents the detailed information of the currently active lens. ```typescript export interface LensInfo { /** The focal length of the active lens in millimeters. */ focalLength: number; /** The device type of the active lens. */ deviceType: DeviceType; /** The base zoom ratio of the active lens (e.g., 0.5x, 1.0x). */ baseZoomRatio: number; /** The current digital zoom factor applied on top of the base zoom. */ digitalZoom: number; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # Capacitor+ > Capacitor+ is an automated fork of Capacitor that merges community PRs faster, with security-reviewed releases. Tip **Why Capacitor+?** Great PRs sit unmerged in the official Capacitor repository for months. Capacitor+ actively merges these community contributions so you don’t have to wait. Community PRs Merged Faster Bug fixes and features stuck in upstream? We merge them so you can benefit immediately. Auto-Synced Daily Every change from official Capacitor is automatically pulled, tested, and verified. Security Reviewed Every release is analyzed by AI for security vulnerabilities, breaking changes, and stability risks. Drop-in Replacement Same API as official Capacitor - just change the package scope and you’re done. ## Philosophy [Section titled “Philosophy”](#philosophy) The Ionic team maintains Capacitor with their own priorities and release schedule. Community contributions can wait months or even years to be merged. Capacitor+ takes a different approach: 1. **Merge PRs from Forks** - Valuable PRs stuck in the upstream queue are actively merged 2. **Continuous Sync** - Every upstream change is automatically pulled and tested 3. **Rapid Releases** - Changes are published to npm as soon as they pass CI 4. **Community-First** - Your contributions matter and get prioritized 5. **Transparency** - All automation is open source and visible ## Packages [Section titled “Packages”](#packages) | Package | npm | | ------------------------- | --------------------------------------------------------------------------------------------------------------------- | | `@capacitor-plus/core` | [![npm](https://img.shields.io/npm/v/@capacitor-plus/core)](https://www.npmjs.com/package/@capacitor-plus/core) | | `@capacitor-plus/cli` | [![npm](https://img.shields.io/npm/v/@capacitor-plus/cli)](https://www.npmjs.com/package/@capacitor-plus/cli) | | `@capacitor-plus/android` | [![npm](https://img.shields.io/npm/v/@capacitor-plus/android)](https://www.npmjs.com/package/@capacitor-plus/android) | | `@capacitor-plus/ios` | [![npm](https://img.shields.io/npm/v/@capacitor-plus/ios)](https://www.npmjs.com/package/@capacitor-plus/ios) | # Getting Started > Learn how to install Capacitor+ as a drop-in replacement for official Capacitor packages. ## New Project Installation [Section titled “New Project Installation”](#new-project-installation) 1. **Install core packages** ```bash npm install @capacitor-plus/core @capacitor-plus/cli ``` 2. **Add platform packages** ```bash npm install @capacitor-plus/android # for Android npm install @capacitor-plus/ios # for iOS ``` 3. **Initialize Capacitor** * npm ```sh npx cap init ``` * pnpm ```sh pnpm cap init ``` * yarn ```sh yarn cap init ``` * bun ```sh bunx cap init ``` 4. **Add platforms** * npm ```sh npx cap add android ``` * pnpm ```sh pnpm cap add android ``` * yarn ```sh yarn cap add android ``` * bun ```sh bunx cap add android ``` - npm ```sh npx cap add ios ``` - pnpm ```sh pnpm cap add ios ``` - yarn ```sh yarn cap add ios ``` - bun ```sh bunx cap add ios ``` ## Migrating from Official Capacitor [Section titled “Migrating from Official Capacitor”](#migrating-from-official-capacitor) If you have an existing Capacitor project, migrating to Capacitor+ is simple: 1. **Remove official packages** ```bash npm uninstall @capacitor/core @capacitor/cli @capacitor/android @capacitor/ios ``` 2. **Install Capacitor+ packages** ```bash npm install @capacitor-plus/core @capacitor-plus/cli npm install @capacitor-plus/android # if using Android npm install @capacitor-plus/ios # if using iOS ``` 3. **Sync your project** * npm ```sh npx cap sync ``` * pnpm ```sh pnpm cap sync ``` * yarn ```sh yarn cap sync ``` * bun ```sh bunx cap sync ``` Note No code changes required! Capacitor+ has the same API as official Capacitor. Your imports and code remain exactly the same. ## Usage [Section titled “Usage”](#usage) Since Capacitor+ is API-compatible, your existing code works without changes: ```typescript import { Capacitor } from '@capacitor/core'; import { registerPlugin } from '@capacitor/core'; // Check platform const platform = Capacitor.getPlatform(); console.log('Running on:', platform); // Check if native if (Capacitor.isNativePlatform()) { console.log('Running on native platform'); } // Register a custom plugin const MyPlugin = registerPlugin('MyPlugin'); ``` ### With Official Capacitor Plugins [Section titled “With Official Capacitor Plugins”](#with-official-capacitor-plugins) All official Capacitor plugins work seamlessly: ```typescript import { Camera, CameraResultType } from '@capacitor/camera'; import { Geolocation } from '@capacitor/geolocation'; import { Storage } from '@capacitor/preferences'; // Camera const photo = await Camera.getPhoto({ quality: 90, resultType: CameraResultType.Uri }); // Geolocation const position = await Geolocation.getCurrentPosition(); // Storage await Storage.set({ key: 'name', value: 'John' }); ``` ### With Capgo Plugins [Section titled “With Capgo Plugins”](#with-capgo-plugins) Capgo plugins work perfectly with Capacitor+: ```typescript import { CapacitorUpdater } from '@capgo/capacitor-updater'; import { ScreenOrientation } from '@capgo/capacitor-screen-orientation'; import { CapacitorFlash } from '@capgo/capacitor-flash'; // Live updates await CapacitorUpdater.notifyAppReady(); // Screen orientation await ScreenOrientation.lock({ orientation: 'portrait' }); // Flashlight await CapacitorFlash.toggle(); ``` ## How the Sync Works [Section titled “How the Sync Works”](#how-the-sync-works) ```plaintext ┌─────────────────────┐ ┌──────────────────┐ ┌──────────────────┐ ┌─────────────────┐ │ ionic-team/ │ │ CI/CD │ │ Claude Code │ │ npm publish │ │ capacitor │────▶│ Pipeline │────▶│ Security Review │────▶│ @capacitor-plus│ │ (upstream) │ │ (daily sync) │ │ (AI analysis) │ │ packages │ └─────────────────────┘ └──────────────────┘ └──────────────────┘ └─────────────────┘ ``` 1. **Daily Sync**: GitHub Actions fetch latest changes from `ionic-team/capacitor` 2. **PR Creation**: Changes are proposed as pull requests to the `plus` branch 3. **CI Validation**: Full test suite runs (lint, unit tests, iOS build, Android build) 4. **Security Review**: AI-powered analysis checks for vulnerabilities and breaking changes 5. **Auto-Merge**: Only if CI passes AND security review approves 6. **Auto-Publish**: New version published to npm under `@capacitor-plus/*` ## Security Review Details [Section titled “Security Review Details”](#security-review-details) Every upstream sync is analyzed for: | Check | What It Catches | | -------------------- | ---------------------------------------------------------------------- | | **Security** | Command injection, XSS, path traversal, hardcoded secrets | | **Breaking Changes** | Removed/renamed APIs, changed signatures, config changes | | **Stability** | Null dereferences, unhandled exceptions, race conditions, memory leaks | | **Data Safety** | Data loss scenarios, privacy violations, insecure storage | | **Code Integrity** | Obfuscated code, suspicious network calls, backdoors | Caution If any issues are detected, the PR is flagged for manual review and will NOT be auto-merged. This ensures you always get stable, secure releases. ## Submitting Your PR [Section titled “Submitting Your PR”](#submitting-your-pr) Have a PR stuck in the official Capacitor repo? Get it merged in Capacitor+: 1. **Open an issue** in the [Capacitor+ repo](https://github.com/Cap-go/capacitor-plus/issues) linking to your upstream PR 2. **Or submit directly** as a PR to the `plus` branch 3. The team will review, run CI, and merge if it passes This way you and others can benefit from your work immediately without waiting for the upstream release cycle. ## FAQ [Section titled “FAQ”](#faq) ### Is this production-ready? [Section titled “Is this production-ready?”](#is-this-production-ready) Yes. Capacitor+ is used in production apps. Every release passes the same test suite as official Capacitor, plus additional security analysis. ### Will my official plugins still work? [Section titled “Will my official plugins still work?”](#will-my-official-plugins-still-work) Yes. All `@capacitor/*` plugins work with Capacitor+ out of the box. ### What if upstream releases a breaking change? [Section titled “What if upstream releases a breaking change?”](#what-if-upstream-releases-a-breaking-change) The AI security review flags breaking changes for manual review. You’ll see the changes documented before they’re merged. ### How do I report issues? [Section titled “How do I report issues?”](#how-do-i-report-issues) File issues on the [Capacitor+ GitHub repo](https://github.com/Cap-go/capacitor-plus/issues). For issues that also affect official Capacitor, we’ll help coordinate upstream. ### Can I contribute? [Section titled “Can I contribute?”](#can-i-contribute) Absolutely! PRs are welcome. You can submit fixes directly or request that specific upstream PRs be merged. # @capgo/capacitor-compass > Capacitor Compass Plugin interface for reading device compass heading. ## Overview [Section titled “Overview”](#overview) Capacitor Compass Plugin interface for reading device compass heading. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `getCurrentHeading` - Get the current compass heading in degrees. On iOS, the heading is updated in the background, and the latest value is returned. On Android, the heading is calculated when the method is called using accelerometer and magnetometer sensors. Not implemented on Web. * `startListening` - Start listening for compass heading changes via events. This starts the compass sensors and emits ‘headingChange’ events. * `stopListening` - Stop listening for compass heading changes. This stops the compass sensors and stops emitting events. * `checkPermissions` - Check the current permission status for accessing compass data. On iOS, this checks location permission status. On Android, this always returns ‘granted’ as no permissions are required. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `getCurrentHeading` | Get the current compass heading in degrees. On iOS, the heading is updated in the background, and the latest value is returned. On Android, the heading is calculated when the method is called using accelerometer and magnetometer sensors. Not implemented on Web. | | `getPluginVersion` | Get the native Capacitor plugin version. | | `startListening` | Start listening for compass heading changes via events. This starts the compass sensors and emits ‘headingChange’ events. | | `stopListening` | Stop listening for compass heading changes. This stops the compass sensors and stops emitting events. | | `addListener` | Add a listener for compass heading change events. | | `addListener` | Add a listener for compass accuracy change events. Only supported on Android. On iOS and Web, this will never emit events. | | `removeAllListeners` | Remove all listeners for this plugin. | | `checkPermissions` | Check the current permission status for accessing compass data. On iOS, this checks location permission status. On Android, this always returns ‘granted’ as no permissions are required. | | `requestPermissions` | Request permission to access compass data. On iOS, this requests location permission (required for heading data). On Android, this resolves immediately as no permissions are required. | | `watchAccuracy` | Start monitoring compass accuracy. On Android, this monitors the magnetometer accuracy and emits accuracyChange events. Developers can listen to these events and implement their own UI for calibration prompts. On iOS and Web, this method does nothing as compass accuracy monitoring is not available. | | `unwatchAccuracy` | Stop monitoring compass accuracy. This stops the accuracy monitoring. | | `getAccuracy` | Get the current compass accuracy level. On Android, returns the current magnetometer sensor accuracy. On iOS and Web, always returns CompassAccuracy.UNKNOWN as accuracy monitoring is not available. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-compass](https://github.com/Cap-go/capacitor-compass/). # Getting Started > Install @capgo/capacitor-compass and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-compass bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { CapgoCompass } from '@capgo/capacitor-compass'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `getCurrentHeading` [Section titled “getCurrentHeading”](#getcurrentheading) Get the current compass heading in degrees. On iOS, the heading is updated in the background, and the latest value is returned. On Android, the heading is calculated when the method is called using accelerometer and magnetometer sensors. Not implemented on Web. ```typescript import { CapgoCompass } from '@capgo/capacitor-compass'; const { value } = await CapgoCompass.getCurrentHeading(); console.log('Compass heading:', value, 'degrees'); ``` ### `startListening` [Section titled “startListening”](#startlistening) Start listening for compass heading changes via events. This starts the compass sensors and emits ‘headingChange’ events. ```typescript import { CapgoCompass } from '@capgo/capacitor-compass'; // With default throttling (100ms interval, 2° minimum change) await CapgoCompass.startListening(); // With custom throttling for high-frequency updates await CapgoCompass.startListening({ minInterval: 50, // 50ms between events minHeadingChange: 1.0 // 1° minimum change }); CapgoCompass.addListener('headingChange', (event) => { console.log('Heading:', event.value); }); ``` ### `stopListening` [Section titled “stopListening”](#stoplistening) Stop listening for compass heading changes. This stops the compass sensors and stops emitting events. ```typescript import { CapgoCompass } from '@capgo/capacitor-compass'; await CapgoCompass.stopListening(); ``` ### `checkPermissions` [Section titled “checkPermissions”](#checkpermissions) Check the current permission status for accessing compass data. On iOS, this checks location permission status. On Android, this always returns ‘granted’ as no permissions are required. ```typescript import { CapgoCompass } from '@capgo/capacitor-compass'; const status = await CapgoCompass.checkPermissions(); console.log('Compass permission:', status.compass); ``` ### `requestPermissions` [Section titled “requestPermissions”](#requestpermissions) Request permission to access compass data. On iOS, this requests location permission (required for heading data). On Android, this resolves immediately as no permissions are required. ```typescript import { CapgoCompass } from '@capgo/capacitor-compass'; const status = await CapgoCompass.requestPermissions(); if (status.compass === 'granted') { // Can now use compass } ``` ### `watchAccuracy` [Section titled “watchAccuracy”](#watchaccuracy) Start monitoring compass accuracy. On Android, this monitors the magnetometer accuracy and emits accuracyChange events. Developers can listen to these events and implement their own UI for calibration prompts. On iOS and Web, this method does nothing as compass accuracy monitoring is not available. ```typescript import { CapgoCompass } from '@capgo/capacitor-compass'; // Start monitoring accuracy await CapgoCompass.watchAccuracy(); // Listen for accuracy changes and implement custom UI CapgoCompass.addListener('accuracyChange', (event) => { console.log('Accuracy changed to:', event.accuracy); if (event.accuracy < CompassAccuracy.MEDIUM) { // Show your custom calibration UI } }); ``` ### `unwatchAccuracy` [Section titled “unwatchAccuracy”](#unwatchaccuracy) Stop monitoring compass accuracy. This stops the accuracy monitoring. ```typescript import { CapgoCompass } from '@capgo/capacitor-compass'; await CapgoCompass.unwatchAccuracy(); ``` ### `getAccuracy` [Section titled “getAccuracy”](#getaccuracy) Get the current compass accuracy level. On Android, returns the current magnetometer sensor accuracy. On iOS and Web, always returns CompassAccuracy.UNKNOWN as accuracy monitoring is not available. ```typescript import { CapgoCompass } from '@capgo/capacitor-compass'; const { accuracy } = await CapgoCompass.getAccuracy(); if (accuracy < CompassAccuracy.MEDIUM) { console.log('Compass needs calibration'); } ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `CompassHeading` [Section titled “CompassHeading”](#compassheading) Result containing the compass heading value. ```typescript export interface CompassHeading { /** Compass heading in degrees (0-360) */ value: number; } ``` ### `ListeningOptions` [Section titled “ListeningOptions”](#listeningoptions) Options for configuring compass listening behavior. ```typescript export interface ListeningOptions { /** * Minimum interval between heading change events in milliseconds. * Lower values = more frequent updates but higher CPU/battery usage. * * @default 100 * @since 8.1.4 */ minInterval?: number; /** * Minimum heading change in degrees required to trigger an event. * Lower values = more sensitive but more events. * Handles wraparound (e.g., 359° to 1° = 2° change). * * @default 2.0 * @since 8.1.4 */ minHeadingChange?: number; } ``` ### `HeadingChangeEvent` [Section titled “HeadingChangeEvent”](#headingchangeevent) Event data for heading change events. ```typescript export interface HeadingChangeEvent { /** Compass heading in degrees (0-360) */ value: number; } ``` ### `AccuracyChangeEvent` [Section titled “AccuracyChangeEvent”](#accuracychangeevent) Event data for accuracy change events. ```typescript export interface AccuracyChangeEvent { /** Current accuracy level of the compass */ accuracy: CompassAccuracy; } ``` ### `PermissionStatus` [Section titled “PermissionStatus”](#permissionstatus) Permission status for compass plugin. ```typescript export interface PermissionStatus { /** * Permission state for accessing compass/location data. * On iOS, this requires location permission to access heading. * On Android, no special permissions are required for compass sensors. * * @since 7.0.0 */ compass: PermissionState; } ``` ### `CompassAccuracy` [Section titled “CompassAccuracy”](#compassaccuracy) Compass accuracy level constants. ```typescript export enum CompassAccuracy { /** High accuracy - approximates to less than 5 degrees of error */ HIGH = 3, /** Medium accuracy - approximates to less than 10 degrees of error */ MEDIUM = 2, /** Low accuracy - approximates to less than 15 degrees of error */ LOW = 1, /** Unreliable accuracy - approximates to more than 15 degrees of error */ UNRELIABLE = 0, /** Unknown accuracy value */ UNKNOWN = -1, } ``` ### `PermissionState` [Section titled “PermissionState”](#permissionstate) Permission state for compass access. ```typescript export type PermissionState = 'prompt' | 'prompt-with-rationale' | 'granted' | 'denied'; ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-contacts > Capacitor Contacts Plugin interface for managing device contacts. ## Overview [Section titled “Overview”](#overview) Capacitor Contacts Plugin interface for managing device contacts. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `countContacts` - Count the total number of contacts on the device. * `createContact` - Create a new contact programmatically. * `createGroup` - Create a new contact group. * `deleteContactById` - Delete a contact by ID. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | -------------------------- | ------------------------------------------------------------ | | `countContacts` | Count the total number of contacts on the device. | | `createContact` | Create a new contact programmatically. | | `createGroup` | Create a new contact group. | | `deleteContactById` | Delete a contact by ID. | | `deleteGroupById` | Delete a group by ID. | | `displayContactById` | Display a contact using the native contact viewer. | | `displayCreateContact` | Display the native create contact UI. | | `displayUpdateContactById` | Display the native update contact UI for a specific contact. | | `getAccounts` | Get all accounts available on the device. | | `getContactById` | Get a specific contact by ID. | | `getContacts` | Get all contacts from the device. | | `getGroupById` | Get a specific group by ID. | | `getGroups` | Get all contact groups. | | `isAvailable` | Check if contacts are available on the device. | | `isSupported` | Check if the plugin is supported on the current platform. | | `openSettings` | Open the device’s contacts settings. | | `pickContact` | Pick a single contact using the native contact picker. | | `pickContacts` | Pick one or more contacts using the native contact picker. | | `updateContactById` | Update an existing contact by ID. | | `checkPermissions` | Check the current permission status for contacts. | | `requestPermissions` | Request permissions to access contacts. | | `getPluginVersion` | Get the native Capacitor plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-contacts](https://github.com/Cap-go/capacitor-contacts/). # Getting Started > Install @capgo/capacitor-contacts and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-contacts bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { CapacitorContacts } from '@capgo/capacitor-contacts'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `countContacts` [Section titled “countContacts”](#countcontacts) Count the total number of contacts on the device. ```typescript import { CapacitorContacts } from '@capgo/capacitor-contacts'; await CapacitorContacts.countContacts(); ``` ### `createContact` [Section titled “createContact”](#createcontact) Create a new contact programmatically. ```typescript import { CapacitorContacts } from '@capgo/capacitor-contacts'; await CapacitorContacts.createContact({} as CreateContactOptions); ``` ### `createGroup` [Section titled “createGroup”](#creategroup) Create a new contact group. ```typescript import { CapacitorContacts } from '@capgo/capacitor-contacts'; await CapacitorContacts.createGroup({} as CreateGroupOptions); ``` ### `deleteContactById` [Section titled “deleteContactById”](#deletecontactbyid) Delete a contact by ID. ```typescript import { CapacitorContacts } from '@capgo/capacitor-contacts'; await CapacitorContacts.deleteContactById({} as DeleteContactByIdOptions); ``` ### `deleteGroupById` [Section titled “deleteGroupById”](#deletegroupbyid) Delete a group by ID. ```typescript import { CapacitorContacts } from '@capgo/capacitor-contacts'; await CapacitorContacts.deleteGroupById({} as DeleteGroupByIdOptions); ``` ### `displayContactById` [Section titled “displayContactById”](#displaycontactbyid) Display a contact using the native contact viewer. ```typescript import { CapacitorContacts } from '@capgo/capacitor-contacts'; await CapacitorContacts.displayContactById({} as DisplayContactByIdOptions); ``` ### `displayCreateContact` [Section titled “displayCreateContact”](#displaycreatecontact) Display the native create contact UI. ```typescript import { CapacitorContacts } from '@capgo/capacitor-contacts'; await CapacitorContacts.displayCreateContact(); ``` ### `displayUpdateContactById` [Section titled “displayUpdateContactById”](#displayupdatecontactbyid) Display the native update contact UI for a specific contact. ```typescript import { CapacitorContacts } from '@capgo/capacitor-contacts'; await CapacitorContacts.displayUpdateContactById({} as DisplayUpdateContactByIdOptions); ``` ### `getAccounts` [Section titled “getAccounts”](#getaccounts) Get all accounts available on the device. ```typescript import { CapacitorContacts } from '@capgo/capacitor-contacts'; await CapacitorContacts.getAccounts(); ``` ### `getContactById` [Section titled “getContactById”](#getcontactbyid) Get a specific contact by ID. ```typescript import { CapacitorContacts } from '@capgo/capacitor-contacts'; await CapacitorContacts.getContactById({} as GetContactByIdOptions); ``` ### `getContacts` [Section titled “getContacts”](#getcontacts) Get all contacts from the device. ```typescript import { CapacitorContacts } from '@capgo/capacitor-contacts'; await CapacitorContacts.getContacts(); ``` ### `getGroupById` [Section titled “getGroupById”](#getgroupbyid) Get a specific group by ID. ```typescript import { CapacitorContacts } from '@capgo/capacitor-contacts'; await CapacitorContacts.getGroupById({} as GetGroupByIdOptions); ``` ### `getGroups` [Section titled “getGroups”](#getgroups) Get all contact groups. ```typescript import { CapacitorContacts } from '@capgo/capacitor-contacts'; await CapacitorContacts.getGroups(); ``` ### `isAvailable` [Section titled “isAvailable”](#isavailable) Check if contacts are available on the device. ```typescript import { CapacitorContacts } from '@capgo/capacitor-contacts'; await CapacitorContacts.isAvailable(); ``` ### `isSupported` [Section titled “isSupported”](#issupported) Check if the plugin is supported on the current platform. ```typescript import { CapacitorContacts } from '@capgo/capacitor-contacts'; await CapacitorContacts.isSupported(); ``` ### `openSettings` [Section titled “openSettings”](#opensettings) Open the device’s contacts settings. ```typescript import { CapacitorContacts } from '@capgo/capacitor-contacts'; await CapacitorContacts.openSettings(); ``` ### `pickContact` [Section titled “pickContact”](#pickcontact) Pick a single contact using the native contact picker. ```typescript import { CapacitorContacts } from '@capgo/capacitor-contacts'; await CapacitorContacts.pickContact(); ``` ### `pickContacts` [Section titled “pickContacts”](#pickcontacts) Pick one or more contacts using the native contact picker. ```typescript import { CapacitorContacts } from '@capgo/capacitor-contacts'; await CapacitorContacts.pickContacts(); ``` ### `updateContactById` [Section titled “updateContactById”](#updatecontactbyid) Update an existing contact by ID. ```typescript import { CapacitorContacts } from '@capgo/capacitor-contacts'; await CapacitorContacts.updateContactById({} as UpdateContactByIdOptions); ``` ### `checkPermissions` [Section titled “checkPermissions”](#checkpermissions) Check the current permission status for contacts. ```typescript import { CapacitorContacts } from '@capgo/capacitor-contacts'; await CapacitorContacts.checkPermissions(); ``` ### `requestPermissions` [Section titled “requestPermissions”](#requestpermissions) Request permissions to access contacts. ```typescript import { CapacitorContacts } from '@capgo/capacitor-contacts'; await CapacitorContacts.requestPermissions(); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `CountContactsResult` [Section titled “CountContactsResult”](#countcontactsresult) Result from counting contacts. ```typescript export interface CountContactsResult { /** * Total number of contacts. * * @since 1.0.0 */ count: number; } ``` ### `CreateContactOptions` [Section titled “CreateContactOptions”](#createcontactoptions) Options for creating a contact. ```typescript export interface CreateContactOptions { /** * Contact information to create. The 'id' field will be generated automatically. * * @since 1.0.0 */ contact: Omit; } ``` ### `CreateContactResult` [Section titled “CreateContactResult”](#createcontactresult) Result from creating a contact. ```typescript export interface CreateContactResult { /** * The ID of the newly created contact. * * @since 1.0.0 */ id: string; } ``` ### `CreateGroupOptions` [Section titled “CreateGroupOptions”](#creategroupoptions) Options for creating a group. ```typescript export interface CreateGroupOptions { /** * Group information to create. The 'id' field will be generated automatically. * * @since 1.0.0 */ group: Omit; } ``` ### `CreateGroupResult` [Section titled “CreateGroupResult”](#creategroupresult) Result from creating a group. ```typescript export interface CreateGroupResult { /** * The ID of the newly created group. * * @since 1.0.0 */ id: string; } ``` ### `DeleteContactByIdOptions` [Section titled “DeleteContactByIdOptions”](#deletecontactbyidoptions) Options for deleting a contact by ID. ```typescript export interface DeleteContactByIdOptions { /** * The ID of the contact to delete. * * @since 1.0.0 */ id: string; } ``` ### `DeleteGroupByIdOptions` [Section titled “DeleteGroupByIdOptions”](#deletegroupbyidoptions) Options for deleting a group by ID. ```typescript export interface DeleteGroupByIdOptions { /** * The ID of the group to delete. * * @since 1.0.0 */ id: string; } ``` ### `DisplayContactByIdOptions` [Section titled “DisplayContactByIdOptions”](#displaycontactbyidoptions) Options for displaying a contact by ID. ```typescript export interface DisplayContactByIdOptions { /** * The ID of the contact to display. * * @since 1.0.0 */ id: string; } ``` ### `DisplayCreateContactOptions` [Section titled “DisplayCreateContactOptions”](#displaycreatecontactoptions) Options for displaying the native create contact UI. ```typescript export interface DisplayCreateContactOptions { /** * Optional pre-filled contact information for the create UI. * * @since 1.0.0 */ contact?: Omit; } ``` ### `DisplayCreateContactResult` [Section titled “DisplayCreateContactResult”](#displaycreatecontactresult) Result from displaying the native create contact UI. ```typescript export interface DisplayCreateContactResult { /** * The ID of the created contact, if one was created. Undefined if the user cancelled. * * @since 1.0.0 */ id?: string; } ``` ### `DisplayUpdateContactByIdOptions` [Section titled “DisplayUpdateContactByIdOptions”](#displayupdatecontactbyidoptions) Options for displaying the native update contact UI. ```typescript export interface DisplayUpdateContactByIdOptions { /** * The ID of the contact to update. * * @since 1.0.0 */ id: string; } ``` ### `GetAccountsResult` [Section titled “GetAccountsResult”](#getaccountsresult) Result from getting accounts. ```typescript export interface GetAccountsResult { /** * List of accounts available on the device. * * @since 1.0.0 */ accounts: Account[]; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-contentsquare > Internal native bridge contract implemented by Capacitor. ## Overview [Section titled “Overview”](#overview) Internal native bridge contract implemented by Capacitor. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `optIn` * `optOut` * `sendScreenName` * `sendTransaction` ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------------------- | ------------------------------------------------ | | `optIn` | See the source definitions for current behavior. | | `optOut` | See the source definitions for current behavior. | | `sendScreenName` | See the source definitions for current behavior. | | `sendTransaction` | See the source definitions for current behavior. | | `sendDynamicVarWithStringValue` | See the source definitions for current behavior. | | `sendDynamicVarWithIntValue` | See the source definitions for current behavior. | | `onReady` | See the source definitions for current behavior. | | `excludeURLForReplay` | See the source definitions for current behavior. | | `setPIISelectors` | See the source definitions for current behavior. | | `setCapturedElementsSelector` | See the source definitions for current behavior. | | `collect` | See the source definitions for current behavior. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-contentsquare](https://github.com/Cap-go/capacitor-contentsquare/). # Android Notes > Android-specific validation and behavior notes for the Contentsquare Capacitor 8 plugin. Android does not require extra host-app setup for the plugin itself. Once installed and synced, the plugin registers the main Capacitor `WebView`, injects the Contentsquare event bridge, and exposes the documented JavaScript APIs. ## What the plugin does on Android [Section titled “What the plugin does on Android”](#what-the-plugin-does-on-android) * Registers the Capacitor `WebView` with the native Contentsquare SDK. * Exposes `optIn`, `optOut`, `sendScreenName`, `sendTransaction`, and dynamic variable APIs. * Injects replay-related commands such as URL exclusion, PII masking, and captured element selectors. ## Validation tips [Section titled “Validation tips”](#validation-tips) ### Check native logs [Section titled “Check native logs”](#check-native-logs) Filter Android Studio `Logcat` with: ```text CSLIB ``` You should see the native Contentsquare SDK startup message and the WebView bridge registration during app launch. ### Track a first session [Section titled “Track a first session”](#track-a-first-session) ```typescript import { ContentsquarePlugin } from '@capgo/capacitor-contentsquare'; await ContentsquarePlugin.optIn(); await ContentsquarePlugin.sendScreenName('Home'); ``` Without at least one screenview, the session is not kept by Contentsquare. ## Dynamic variable constraints [Section titled “Dynamic variable constraints”](#dynamic-variable-constraints) * Keys are limited by Contentsquare to 512 characters. * Values must be either a string or a non-negative integer. * If you want a value on every session, send it again when the app returns to foreground. # Getting Started > Install and configure the Contentsquare Capacitor plugin for analytics and session replay. 1. **Install the plugin** * npm ```sh npm i @capgo/capacitor-contentsquare ``` * pnpm ```sh pnpm add @capgo/capacitor-contentsquare ``` * yarn ```sh yarn add @capgo/capacitor-contentsquare ``` * bun ```sh bun add @capgo/capacitor-contentsquare ``` 2. **Sync native platforms** * npm ```sh npx cap sync ``` * pnpm ```sh pnpm cap sync ``` * yarn ```sh yarn cap sync ``` * bun ```sh bunx cap sync ``` 3. **Review the upstream product configuration** * Follow the official [Contentsquare Capacitor guide](https://docs.contentsquare.com/en/capacitor/) for project keys, replay settings, and dashboard setup. ## Basic usage [Section titled “Basic usage”](#basic-usage) ```typescript import { ContentsquarePlugin, CurrencyCode } from '@capgo/capacitor-contentsquare'; await ContentsquarePlugin.optIn(); await ContentsquarePlugin.sendScreenName('Home'); await ContentsquarePlugin.sendTransaction({ transactionValue: 29.99, transactionCurrency: CurrencyCode.EUR, transactionId: 'order-123', }); await ContentsquarePlugin.sendDynamicVar({ dynVarKey: 'store', dynVarValue: 'rome', }); ``` ## Screen naming tips [Section titled “Screen naming tips”](#screen-naming-tips) * Use stable names instead of user-specific values. * Keep the same naming conventions across iOS and Android navigation stacks. * When the app returns to foreground, resend the screen name and any critical dynamic variables. ## Replay privacy controls [Section titled “Replay privacy controls”](#replay-privacy-controls) Use the built-in masking helpers to keep sensitive content out of Session Replay: ```typescript await ContentsquarePlugin.excludeURLForReplay('/checkout/'); await ContentsquarePlugin.setCapturedElementsSelector('[data-cs-capture]'); await ContentsquarePlugin.setPIISelectors({ PIISelectors: ['input[type="email"]', '.credit-card'], Attributes: [{ selector: 'input[name="email"]', attrName: 'value' }], }); ``` ## Platform setup [Section titled “Platform setup”](#platform-setup) * For iOS in-app features, complete the extra deeplink wiring in the [iOS setup](/docs/plugins/contentsquare/ios/) page. * Android does not need extra manifest wiring for the plugin itself; see [Android notes](/docs/plugins/contentsquare/android/) for logging and validation tips. ## Notes [Section titled “Notes”](#notes) * This plugin is a Capacitor 8 community port of the official Contentsquare Capacitor package. * The JavaScript API stays aligned with the current Contentsquare Capacitor docs, while the packaging and native build setup target Capacitor 8. # iOS Setup > Configure the required iOS deeplink hooks for Contentsquare in-app features in Capacitor apps. Contentsquare tracking starts automatically once the plugin is installed, but iOS in-app features such as SDK logs, screenshot capture, and replay configuration still need the upstream URL handling setup. ## 1. Add the URL scheme [Section titled “1. Add the URL scheme”](#1-add-the-url-scheme) Add `cs-$(PRODUCT_BUNDLE_IDENTIFIER)` to your app URL schemes in Xcode or your host app’s `Info.plist`. ```xml CFBundleURLTypes CFBundleURLSchemes cs-$(PRODUCT_BUNDLE_IDENTIFIER) ``` ## 2. Forward Contentsquare deeplinks [Section titled “2. Forward Contentsquare deeplinks”](#2-forward-contentsquare-deeplinks) Wherever your Capacitor host app handles incoming URLs, forward them to the native SDK: ### AppDelegate [Section titled “AppDelegate”](#appdelegate) ```swift import ContentsquareModule func application( _ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:] ) -> Bool { Contentsquare.handle(url: url) return true } ``` ### SceneDelegate [Section titled “SceneDelegate”](#scenedelegate) ```swift import ContentsquareModule func scene(_ scene: UIScene, openURLContexts urlContexts: Set) { if let url = urlContexts.first?.url { Contentsquare.handle(url: url) } } ``` ### SwiftUI [Section titled “SwiftUI”](#swiftui) ```swift import ContentsquareModule .onOpenURL { url in Contentsquare.handle(url: url) } ``` ## 3. Validate the installation [Section titled “3. Validate the installation”](#3-validate-the-installation) * Launch the app on a device or simulator. * Filter Xcode or Console logs with `CSLIB`. * Open the Contentsquare mobile tooling and trigger in-app features to confirm the deeplink is handled. # @capgo/capacitor-crisp > Crisp Chat SDK Plugin for Capacitor. Provides live chat and customer support functionality through Crisp.chat. ## Overview [Section titled “Overview”](#overview) Crisp Chat SDK Plugin for Capacitor. Provides live chat and customer support functionality through Crisp.chat. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `configure` - Configure the Crisp SDK with your website ID. Must be called before using any other methods. * `openMessenger` - Open the Crisp messenger chat window. Shows the chat interface to the user. * `setTokenID` - Set a unique token ID for the current user session. Used to identify and restore previous conversations. * `setUser` - Set user information for the current session. Updates the user profile visible to support agents. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------ | -------------------------------------------------------------------------------------------------------- | | `configure` | Configure the Crisp SDK with your website ID. Must be called before using any other methods. | | `openMessenger` | Open the Crisp messenger chat window. Shows the chat interface to the user. | | `setTokenID` | Set a unique token ID for the current user session. Used to identify and restore previous conversations. | | `setUser` | Set user information for the current session. Updates the user profile visible to support agents. | | `pushEvent` | Push a custom event to Crisp. Useful for tracking user actions and behavior. | | `setCompany` | Set company information for the current session. Associates the user with a company in Crisp. | | `setInt` | Set a custom integer data field. Stores numerical data associated with the user session. | | `setString` | Set a custom string data field. Stores text data associated with the user session. | | `sendMessage` | Send a message from the user to the chat. Programmatically send a message as if the user typed it. | | `setSegment` | Set a user segment for targeting and organization. Used to categorize users in the Crisp dashboard. | | `reset` | Reset the Crisp session. Clears all user data and starts a fresh session. Useful when user logs out. | | `getPluginVersion` | Get the plugin version number. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-crisp](https://github.com/Cap-go/capacitor-crisp/). # Getting Started > Install @capgo/capacitor-crisp and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-crisp bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { CapacitorCrisp } from '@capgo/capacitor-crisp'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `configure` [Section titled “configure”](#configure) Configure the Crisp SDK with your website ID. Must be called before using any other methods. ```typescript import { CapacitorCrisp } from '@capgo/capacitor-crisp'; await CrispPlugin.configure({ websiteID: 'YOUR_WEBSITE_ID' }); ``` ### `openMessenger` [Section titled “openMessenger”](#openmessenger) Open the Crisp messenger chat window. Shows the chat interface to the user. ```typescript import { CapacitorCrisp } from '@capgo/capacitor-crisp'; await CapacitorCrisp.openMessenger(); ``` ### `setTokenID` [Section titled “setTokenID”](#settokenid) Set a unique token ID for the current user session. Used to identify and restore previous conversations. ```typescript import { CapacitorCrisp } from '@capgo/capacitor-crisp'; await CapacitorCrisp.setTokenID({} as { tokenID: string }); ``` ### `setUser` [Section titled “setUser”](#setuser) Set user information for the current session. Updates the user profile visible to support agents. ```typescript import { CapacitorCrisp } from '@capgo/capacitor-crisp'; await CrispPlugin.setUser({ nickname: 'John Doe', email: 'john@example.com', phone: '+1234567890' }); ``` ### `pushEvent` [Section titled “pushEvent”](#pushevent) Push a custom event to Crisp. Useful for tracking user actions and behavior. ```typescript import { CapacitorCrisp } from '@capgo/capacitor-crisp'; await CrispPlugin.pushEvent({ name: 'completed_purchase', color: 'green' }); ``` ### `setCompany` [Section titled “setCompany”](#setcompany) Set company information for the current session. Associates the user with a company in Crisp. ```typescript import { CapacitorCrisp } from '@capgo/capacitor-crisp'; await CrispPlugin.setCompany({ name: 'Acme Corp', url: 'https://acme.com', employment: ['CEO', 'Executive'], geolocation: ['USA', 'San Francisco'] }); ``` ### `setInt` [Section titled “setInt”](#setint) Set a custom integer data field. Stores numerical data associated with the user session. ```typescript import { CapacitorCrisp } from '@capgo/capacitor-crisp'; await CrispPlugin.setInt({ key: 'user_level', value: 42 }); ``` ### `setString` [Section titled “setString”](#setstring) Set a custom string data field. Stores text data associated with the user session. ```typescript import { CapacitorCrisp } from '@capgo/capacitor-crisp'; await CrispPlugin.setString({ key: 'subscription_tier', value: 'premium' }); ``` ### `sendMessage` [Section titled “sendMessage”](#sendmessage) Send a message from the user to the chat. Programmatically send a message as if the user typed it. ```typescript import { CapacitorCrisp } from '@capgo/capacitor-crisp'; await CrispPlugin.sendMessage({ value: 'Hello, I need help!' }); ``` ### `setSegment` [Section titled “setSegment”](#setsegment) Set a user segment for targeting and organization. Used to categorize users in the Crisp dashboard. ```typescript import { CapacitorCrisp } from '@capgo/capacitor-crisp'; await CrispPlugin.setSegment({ segment: 'premium-users' }); ``` ### `reset` [Section titled “reset”](#reset) Reset the Crisp session. Clears all user data and starts a fresh session. Useful when user logs out. ```typescript import { CapacitorCrisp } from '@capgo/capacitor-crisp'; await CapacitorCrisp.reset(); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `ConfigureOptions` [Section titled “ConfigureOptions”](#configureoptions) Configuration for initializing Crisp. ```typescript export interface ConfigureOptions { /** * Your Crisp website ID from dashboard. */ websiteID: string; /** * Optional - Locale to force in the Crisp chat widget (ISO 639-1), eg. `en`, `fr`, `es`. * Web + Android: overrides the runtime locale. iOS follows the device/app locale. */ locale?: string; /** * Optional - Unique token identifier for the user session continuity. */ tokenID?: string; } ``` ### `eventColor` [Section titled “eventColor”](#eventcolor) Available colors for Crisp events. Used to visually categorize events in the Crisp dashboard. ```typescript export type eventColor = | 'red' | 'orange' | 'yellow' | 'green' | 'blue' | 'purple' | 'pink' | 'brown' | 'grey' | 'black'; ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-data-storage-sqlite > SQLite Storage of key/value strings pair. ## Overview [Section titled “Overview”](#overview) SQLite Storage of key/value strings pair. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `openStore` - Open a store. * `closeStore` - Close the Store. * `isStoreOpen` - Check if the Store is opened. * `isStoreExists` - Check if the Store exists. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------ | ------------------------------------------- | | `openStore` | Open a store. | | `closeStore` | Close the Store. | | `isStoreOpen` | Check if the Store is opened. | | `isStoreExists` | Check if the Store exists. | | `deleteStore` | Delete a store. | | `setTable` | Set or Add a table to an existing store. | | `set` | Store a data with given key and value. | | `get` | Retrieve a data value for a given data key. | | `remove` | Remove a data with given key. | | `clear` | Clear the Data Store (delete all keys). | | `iskey` | Check if a data key exists. | | `keys` | Get the data key list. | | `values` | Get the data value list. | | `filtervalues` | Get the data value list for filter keys. | | `keysvalues` | Get the data key/value pair list. | | `isTable` | Check if a table exists. | | `tables` | Get the table list for the current store. | | `deleteTable` | Delete a table. | | `importFromJson` | Import a database From a JSON. | | `isJsonValid` | Check the validity of a JSON Object. | | `exportToJson` | Export the given database to a JSON Object. | | `getPluginVersion` | Get the native Capacitor plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-data-storage-sqlite](https://github.com/Cap-go/capacitor-data-storage-sqlite/). # Getting Started > Install @capgo/capacitor-data-storage-sqlite and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-data-storage-sqlite bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { CapgoCapacitorDataStorageSqlite } from '@capgo/capacitor-data-storage-sqlite'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `openStore` [Section titled “openStore”](#openstore) Open a store ```typescript import { CapgoCapacitorDataStorageSqlite } from '@capgo/capacitor-data-storage-sqlite'; await CapgoCapacitorDataStorageSqlite.openStore({} as capOpenStorageOptions); ``` ### `closeStore` [Section titled “closeStore”](#closestore) Close the Store ```typescript import { CapgoCapacitorDataStorageSqlite } from '@capgo/capacitor-data-storage-sqlite'; await CapgoCapacitorDataStorageSqlite.closeStore({} as capStorageOptions); ``` ### `isStoreOpen` [Section titled “isStoreOpen”](#isstoreopen) Check if the Store is opened ```typescript import { CapgoCapacitorDataStorageSqlite } from '@capgo/capacitor-data-storage-sqlite'; await CapgoCapacitorDataStorageSqlite.isStoreOpen({} as capStorageOptions); ``` ### `isStoreExists` [Section titled “isStoreExists”](#isstoreexists) Check if the Store exists ```typescript import { CapgoCapacitorDataStorageSqlite } from '@capgo/capacitor-data-storage-sqlite'; await CapgoCapacitorDataStorageSqlite.isStoreExists({} as capStorageOptions); ``` ### `deleteStore` [Section titled “deleteStore”](#deletestore) Delete a store ```typescript import { CapgoCapacitorDataStorageSqlite } from '@capgo/capacitor-data-storage-sqlite'; await CapgoCapacitorDataStorageSqlite.deleteStore({} as capOpenStorageOptions); ``` ### `setTable` [Section titled “setTable”](#settable) Set or Add a table to an existing store ```typescript import { CapgoCapacitorDataStorageSqlite } from '@capgo/capacitor-data-storage-sqlite'; await CapgoCapacitorDataStorageSqlite.setTable({} as capTableStorageOptions); ``` ### `set` [Section titled “set”](#set) Store a data with given key and value ```typescript import { CapgoCapacitorDataStorageSqlite } from '@capgo/capacitor-data-storage-sqlite'; await CapgoCapacitorDataStorageSqlite.set({} as capDataStorageOptions); ``` ### `get` [Section titled “get”](#get) Retrieve a data value for a given data key ```typescript import { CapgoCapacitorDataStorageSqlite } from '@capgo/capacitor-data-storage-sqlite'; await CapgoCapacitorDataStorageSqlite.get({} as capDataStorageOptions); ``` ### `remove` [Section titled “remove”](#remove) Remove a data with given key ```typescript import { CapgoCapacitorDataStorageSqlite } from '@capgo/capacitor-data-storage-sqlite'; await CapgoCapacitorDataStorageSqlite.remove({} as capDataStorageOptions); ``` ### `clear` [Section titled “clear”](#clear) Clear the Data Store (delete all keys) ```typescript import { CapgoCapacitorDataStorageSqlite } from '@capgo/capacitor-data-storage-sqlite'; await CapgoCapacitorDataStorageSqlite.clear(); ``` ### `iskey` [Section titled “iskey”](#iskey) Check if a data key exists ```typescript import { CapgoCapacitorDataStorageSqlite } from '@capgo/capacitor-data-storage-sqlite'; await CapgoCapacitorDataStorageSqlite.iskey({} as capDataStorageOptions); ``` ### `keys` [Section titled “keys”](#keys) Get the data key list ```typescript import { CapgoCapacitorDataStorageSqlite } from '@capgo/capacitor-data-storage-sqlite'; await CapgoCapacitorDataStorageSqlite.keys(); ``` ### `values` [Section titled “values”](#values) Get the data value list ```typescript import { CapgoCapacitorDataStorageSqlite } from '@capgo/capacitor-data-storage-sqlite'; await CapgoCapacitorDataStorageSqlite.values(); ``` ### `filtervalues` [Section titled “filtervalues”](#filtervalues) Get the data value list for filter keys ```typescript import { CapgoCapacitorDataStorageSqlite } from '@capgo/capacitor-data-storage-sqlite'; await CapgoCapacitorDataStorageSqlite.filtervalues({} as capFilterStorageOptions); ``` ### `keysvalues` [Section titled “keysvalues”](#keysvalues) Get the data key/value pair list ```typescript import { CapgoCapacitorDataStorageSqlite } from '@capgo/capacitor-data-storage-sqlite'; await CapgoCapacitorDataStorageSqlite.keysvalues(); ``` ### `isTable` [Section titled “isTable”](#istable) Check if a table exists ```typescript import { CapgoCapacitorDataStorageSqlite } from '@capgo/capacitor-data-storage-sqlite'; await CapgoCapacitorDataStorageSqlite.isTable({} as capTableStorageOptions); ``` ### `tables` [Section titled “tables”](#tables) Get the table list for the current store ```typescript import { CapgoCapacitorDataStorageSqlite } from '@capgo/capacitor-data-storage-sqlite'; await CapgoCapacitorDataStorageSqlite.tables(); ``` ### `deleteTable` [Section titled “deleteTable”](#deletetable) Delete a table ```typescript import { CapgoCapacitorDataStorageSqlite } from '@capgo/capacitor-data-storage-sqlite'; await CapgoCapacitorDataStorageSqlite.deleteTable({} as capTableStorageOptions); ``` ### `importFromJson` [Section titled “importFromJson”](#importfromjson) Import a database From a JSON ```typescript import { CapgoCapacitorDataStorageSqlite } from '@capgo/capacitor-data-storage-sqlite'; await CapgoCapacitorDataStorageSqlite.importFromJson({} as capStoreImportOptions); ``` ### `isJsonValid` [Section titled “isJsonValid”](#isjsonvalid) Check the validity of a JSON Object ```typescript import { CapgoCapacitorDataStorageSqlite } from '@capgo/capacitor-data-storage-sqlite'; await CapgoCapacitorDataStorageSqlite.isJsonValid({} as capStoreImportOptions); ``` ### `exportToJson` [Section titled “exportToJson”](#exporttojson) Export the given database to a JSON Object ```typescript import { CapgoCapacitorDataStorageSqlite } from '@capgo/capacitor-data-storage-sqlite'; await CapgoCapacitorDataStorageSqlite.exportToJson(); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `capOpenStorageOptions` [Section titled “capOpenStorageOptions”](#capopenstorageoptions) ```typescript export interface capOpenStorageOptions { /** * The storage database name */ database?: string; // default: // ios, android: storageSQLite // web : storageIDB /** * The storage table name */ table?: string; // default: // ios, android: storage_table // web: storage_store /** * Set to true for database encryption */ encrypted?: boolean; // only for ios and android /*** * Set the mode for database encryption * ["encryption", "secret","newsecret"] */ mode?: string; // only for ios and android } ``` ### `capStorageOptions` [Section titled “capStorageOptions”](#capstorageoptions) ```typescript export interface capStorageOptions { /** * The storage name */ database: string; } ``` ### `capDataStorageResult` [Section titled “capDataStorageResult”](#capdatastorageresult) ```typescript export interface capDataStorageResult { /** * result set to true when successful else false */ result?: boolean; /** * a returned message */ message?: string; } ``` ### `capTableStorageOptions` [Section titled “capTableStorageOptions”](#captablestorageoptions) ```typescript export interface capTableStorageOptions { /** * The storage table name */ table: string; } ``` ### `capDataStorageOptions` [Section titled “capDataStorageOptions”](#capdatastorageoptions) ```typescript export interface capDataStorageOptions { /** * The data name */ key: string; /** * The data value when required */ value?: string; } ``` ### `capValueResult` [Section titled “capValueResult”](#capvalueresult) ```typescript export interface capValueResult { /** * the data value for a given data key */ value: string; } ``` ### `capKeysResult` [Section titled “capKeysResult”](#capkeysresult) ```typescript export interface capKeysResult { /** * the data key list as an Array */ keys: string[]; } ``` ### `capValuesResult` [Section titled “capValuesResult”](#capvaluesresult) ```typescript export interface capValuesResult { /** * the data values list as an Array */ values: string[]; } ``` ### `capFilterStorageOptions` [Section titled “capFilterStorageOptions”](#capfilterstorageoptions) ```typescript export interface capFilterStorageOptions { /** * The filter data for filtering keys * * ['%filter', 'filter', 'filter%'] for * [starts with filter, contains filter, ends with filter] */ filter: string; } ``` ### `capKeysValuesResult` [Section titled “capKeysValuesResult”](#capkeysvaluesresult) ```typescript export interface capKeysValuesResult { /** * the data keys/values list as an Array of {key:string,value:string} */ keysvalues: any[]; } ``` ### `capTablesResult` [Section titled “capTablesResult”](#captablesresult) ```typescript export interface capTablesResult { /** * the tables list as an Array */ tables: string[]; } ``` ### `capStoreImportOptions` [Section titled “capStoreImportOptions”](#capstoreimportoptions) ```typescript export interface capStoreImportOptions { /** * Set the JSON object to import * */ jsonstring?: string; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-document-scanner > Capacitor plugin to scan document iOS and Android. ## Overview [Section titled “Overview”](#overview) Capacitor plugin to scan document iOS and Android. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `scanDocument` - Opens the device camera and starts the document scanning experience. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | -------------- | -------------------------------------------------------------------- | | `scanDocument` | Opens the device camera and starts the document scanning experience. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-document-scanner](https://github.com/Cap-go/capacitor-document-scanner/). # Getting Started > Install @capgo/capacitor-document-scanner and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-document-scanner bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { DocumentScanner } from '@capgo/capacitor-document-scanner'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `scanDocument` [Section titled “scanDocument”](#scandocument) Opens the device camera and starts the document scanning experience. ```typescript import { DocumentScanner } from '@capgo/capacitor-document-scanner'; await DocumentScanner.scanDocument(); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `ScanDocumentOptions` [Section titled “ScanDocumentOptions”](#scandocumentoptions) ```typescript export interface ScanDocumentOptions { /** * Android only: quality of the cropped image from 0 - 100 (100 is best). * @default 100 */ croppedImageQuality?: number; /** * Allow the user to adjust the detected crop before saving. * On iOS this forces the native VisionKit preview/editor after each capture using * the private VisionKit navigation hooks needed to keep the scanner flow alive. * On Android this enables ML Kit's crop adjustment flow. * @default true */ letUserAdjustCrop?: boolean; /** * When enabled, shows the current scanned page before continuing so the user can * review it and explicitly continue or finish the flow. * On iOS this forces the native VisionKit preview/editor between captures. * On Android this switches to a one-page-at-a-time flow between ML Kit sessions. * The review/editor screen is still shown automatically when the scan limit is reached. * @default false */ reviewCapturedDocument?: boolean; /** * Maximum number of documents to scan. * On iOS: VisionKit caps scans at 24 pages (system limit), and the hacked native flow * can still stop earlier when you pass a smaller limit. * On Android: customizable limit; defaults to 20 for performance (clamped 1-24). * Set to 1 for single-scan mode where the scanner stops after one document. * @default 20 on Android, 24 on iOS */ maxNumDocuments?: number; /** * Format to return scanned images in (file paths or base64 strings). * @default ResponseType.ImageFilePath */ responseType?: ResponseType; /** * Brightness adjustment applied to scanned images. * Range: -255 to 255 (0 = no change, positive = brighter, negative = darker) * Useful for compensating low-light scans. * @default 0 */ brightness?: number; /** * Contrast adjustment applied to scanned images. * Range: 0.0 to 10.0 (1.0 = no change, >1 = more contrast, <1 = less contrast) * Helps improve text clarity in poorly lit scans. * @default 1.0 */ contrast?: number; /** * Android only: scanner mode that controls ML Kit features and filters. * - 'base': Basic scan with crop/rotate, no filters or ML cleaning * - 'base_with_filter': Adds grayscale and auto-enhancement filters * - 'full': All features including ML-based image cleaning (erases stains, fingers, etc.) * @default ScannerMode.Full */ scannerMode?: ScannerMode; } ``` ### `ScanDocumentResponse` [Section titled “ScanDocumentResponse”](#scandocumentresponse) ```typescript export interface ScanDocumentResponse { /** * Scanned images in the requested response format. */ scannedImages?: string[]; /** * Indicates whether the scan completed or was cancelled. */ status?: ScanDocumentResponseStatus; /** * Get the native Capacitor plugin version * * @returns {Promise<{ id: string }>} an Promise with version for this device * @throws An error if the something went wrong */ getPluginVersion(): Promise<{ version: string }>; } ``` ### `ResponseType` [Section titled “ResponseType”](#responsetype) ```typescript export enum ResponseType { /** * Return scanned images as base64-encoded strings. */ Base64 = 'base64', /** * Return scanned images as file paths on disk. */ ImageFilePath = 'imageFilePath', } ``` ### `ScannerMode` [Section titled “ScannerMode”](#scannermode) ```typescript export enum ScannerMode { /** * Basic document scanning with crop and rotate features only. * No filters or ML-based enhancements. */ Base = 'base', /** * Basic features plus automatic filters (grayscale, auto-enhancement). */ BaseWithFilter = 'base_with_filter', /** * Full feature set including ML-based image cleaning. * Automatically removes stains, fingers, and other artifacts. */ Full = 'full', } ``` ### `ScanDocumentResponseStatus` [Section titled “ScanDocumentResponseStatus”](#scandocumentresponsestatus) ```typescript export enum ScanDocumentResponseStatus { /** * The scan completed successfully. */ Success = 'success', /** * The user cancelled the scan flow. */ Cancel = 'cancel', } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-downloader > Capacitor plugin for downloading files with background support. Provides resumable downloads with progress tracking. ## Overview [Section titled “Overview”](#overview) Capacitor plugin for downloading files with background support. Provides resumable downloads with progress tracking. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `download` - Start a new download task. * `pause` - Pause an active download. Download can be resumed later from the same position. * `resume` - Resume a paused download. Continues from where it was paused. * `stop` - Stop and cancel a download permanently. Downloaded data will be deleted. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | -------------------- | -------------------------------------------------------------------------------- | | `download` | Start a new download task. | | `pause` | Pause an active download. Download can be resumed later from the same position. | | `resume` | Resume a paused download. Continues from where it was paused. | | `stop` | Stop and cancel a download permanently. Downloaded data will be deleted. | | `checkStatus` | Check the current status of a download. | | `getFileInfo` | Get information about a downloaded file. | | `addListener` | Listen for download progress updates. Fired periodically as download progresses. | | `addListener` | Listen for download completion. Fired when a download finishes successfully. | | `addListener` | Listen for download failures. Fired when a download encounters an error. | | `removeAllListeners` | Remove all event listeners. Cleanup method to prevent memory leaks. | | `getPluginVersion` | Get the plugin version number. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-downloader](https://github.com/Cap-go/capacitor-downloader/). # Getting Started > Install @capgo/capacitor-downloader and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-downloader bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { CapacitorDownloader } from '@capgo/capacitor-downloader'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `download` [Section titled “download”](#download) Start a new download task. ```typescript import { CapacitorDownloader } from '@capgo/capacitor-downloader'; const task = await Downloader.download({ id: 'my-download', url: 'https://example.com/file.pdf', destination: 'downloads/file.pdf' }); ``` ### `pause` [Section titled “pause”](#pause) Pause an active download. Download can be resumed later from the same position. ```typescript import { CapacitorDownloader } from '@capgo/capacitor-downloader'; await CapacitorDownloader.pause({} as { id: string }); ``` ### `resume` [Section titled “resume”](#resume) Resume a paused download. Continues from where it was paused. ```typescript import { CapacitorDownloader } from '@capgo/capacitor-downloader'; await CapacitorDownloader.resume({} as { id: string }); ``` ### `stop` [Section titled “stop”](#stop) Stop and cancel a download permanently. Downloaded data will be deleted. ```typescript import { CapacitorDownloader } from '@capgo/capacitor-downloader'; await CapacitorDownloader.stop({} as { id: string }); ``` ### `checkStatus` [Section titled “checkStatus”](#checkstatus) Check the current status of a download. ```typescript import { CapacitorDownloader } from '@capgo/capacitor-downloader'; await CapacitorDownloader.checkStatus({} as { id: string }); ``` ### `getFileInfo` [Section titled “getFileInfo”](#getfileinfo) Get information about a downloaded file. ```typescript import { CapacitorDownloader } from '@capgo/capacitor-downloader'; await CapacitorDownloader.getFileInfo({} as { path: string }); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `DownloadOptions` [Section titled “DownloadOptions”](#downloadoptions) Configuration options for starting a download. ```typescript export interface DownloadOptions { /** Unique identifier for this download task */ id: string; /** URL of the file to download */ url: string; /** Local file path where the download will be saved */ destination: string; /** Optional HTTP headers to include in the request */ headers?: { [key: string]: string }; /** Network type requirement for download */ network?: 'cellular' | 'wifi-only'; /** Download priority level */ priority?: 'high' | 'normal' | 'low'; } ``` ### `DownloadTask` [Section titled “DownloadTask”](#downloadtask) Represents the current state and progress of a download task. ```typescript export interface DownloadTask { /** Unique identifier for the download task */ id: string; /** Download progress from 0 to 100 */ progress: number; /** Current state of the download */ state: 'PENDING' | 'RUNNING' | 'PAUSED' | 'DONE' | 'ERROR'; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/electron-updater > Push instant updates to your Electron desktop apps without rebuilding binaries. Same reliable live update system now for desktop. Tip New to Capgo? The Electron Updater brings the same powerful live update capabilities from mobile to desktop. If you’re already using `@capgo/capacitor-updater`, you’ll feel right at home. ## Why Electron Updater? [Section titled “Why Electron Updater?”](#why-electron-updater) Electron’s built-in auto-updater requires shipping a full new binary for every update. This plugin solves that by enabling JavaScript/HTML/CSS updates without rebuilding. Instant Updates Push JavaScript, HTML, and CSS updates directly to users without rebuilding the entire app binary. Delta Updates Only download changed files, making updates ultra-fast and bandwidth-efficient. Rollback Protection Automatic rollback if an update fails, keeping your app stable for users. End-to-End Encryption Secure update delivery with RSA session keys and AES bundle encryption. ## Key Features [Section titled “Key Features”](#key-features) * **Live Updates** - Push updates instantly without app store delays * **Auto-Update** - Automatic update checking and installation * **Rollback Protection** - Automatic rollback if `notifyAppReady()` isn’t called * **Bundle Management** - Full control over downloaded bundles * **Channel System** - Deploy to different user groups (production, beta, staging) * **Delay Conditions** - Control when updates are applied (background, kill, date, native version) * **Debug Menu** - Built-in debug tools accessible via `Ctrl+Shift+D` / `Cmd+Shift+D` * **Statistics Reporting** - Track update success rates and user versions ## Feature Parity with Capacitor Updater [Section titled “Feature Parity with Capacitor Updater”](#feature-parity-with-capacitor-updater) The Electron Updater maintains 100% API compatibility with `@capgo/capacitor-updater`. The same methods, events, and configuration options work across both platforms: | Feature | Capacitor | Electron | | --------------------- | ------------ | ----------------- | | Live Updates | Yes | Yes | | Channels | Yes | Yes | | Rollback Protection | Yes | Yes | | End-to-End Encryption | Yes | Yes | | Statistics | Yes | Yes | | Delay Conditions | Yes | Yes | | Debug Menu | Shake device | Keyboard shortcut | ## Installation [Section titled “Installation”](#installation) ```bash npm install @capgo/electron-updater ``` ## Quick Links [Section titled “Quick Links”](#quick-links) [Getting Started ](/docs/plugins/electron-updater/getting-started/)Complete setup guide for adding live updates to your Electron app. [API Reference ](/docs/plugins/electron-updater/api/)All available methods, events, and configuration options. [Capacitor Updater Docs ](/docs/plugins/updater/)The mobile counterpart - same API, same concepts, for Capacitor apps. ## Documentation [Section titled “Documentation”](#documentation) * **[Getting Started](/docs/plugins/electron-updater/getting-started/)** - Setup and configuration guide * **[API Reference](/docs/plugins/electron-updater/api/)** - All methods, events, and options * **[Getting Started (from Capacitor)](/docs/plugins/electron-updater/getting-started/)** - Moving from Capacitor to Electron ## Community [Section titled “Community”](#community) Join the [Discord](https://discord.gg/VnYRvBfgA6) to get help and connect with other developers. # Electron Updater API Reference > Complete API reference for @capgo/electron-updater - all methods, events, and configuration options. This page documents all available methods, events, and configuration options for the Electron Updater. ## Core Methods [Section titled “Core Methods”](#core-methods) ### notifyAppReady() [Section titled “notifyAppReady()”](#notifyappready) **Must be called on every app launch.** Confirms the bundle loaded successfully and prevents automatic rollback. ```typescript await updater.notifyAppReady(); ``` Caution If not called within `appReadyTimeout` (default 10 seconds), the update is considered failed and the app rolls back to the previous version. ### download(options) [Section titled “download(options)”](#downloadoptions) Download a bundle from a URL. ```typescript const bundle = await updater.download({ url: 'https://example.com/bundle.zip', version: '1.0.1', checksum: 'sha256-hash', // Optional but recommended sessionKey: '...', // For encrypted bundles }); ``` **Parameters:** | Option | Type | Required | Description | | ------------ | ------ | -------- | --------------------------------- | | `url` | string | Yes | URL to download the bundle from | | `version` | string | Yes | Version identifier for the bundle | | `checksum` | string | No | SHA256 checksum for verification | | `sessionKey` | string | No | Session key for encrypted bundles | **Returns:** `BundleInfo` object with `id`, `version`, `status` ### next(options) [Section titled “next(options)”](#nextoptions) Queue a bundle to be loaded on next app restart. ```typescript await updater.next({ id: 'bundle-id' }); ``` **Parameters:** | Option | Type | Required | Description | | ------ | ------ | -------- | ------------------ | | `id` | string | Yes | Bundle ID to queue | ### set(options) [Section titled “set(options)”](#setoptions) Immediately switch to a bundle and reload the app. ```typescript await updater.set({ id: 'bundle-id' }); ``` **Parameters:** | Option | Type | Required | Description | | ------ | ------ | -------- | --------------------- | | `id` | string | Yes | Bundle ID to activate | ### reload() [Section titled “reload()”](#reload) Manually reload the app with the current bundle. ```typescript await updater.reload(); ``` ### delete(options) [Section titled “delete(options)”](#deleteoptions) Delete a bundle from storage. ```typescript await updater.delete({ id: 'bundle-id' }); ``` **Parameters:** | Option | Type | Required | Description | | ------ | ------ | -------- | ------------------- | | `id` | string | Yes | Bundle ID to delete | ### reset(options) [Section titled “reset(options)”](#resetoptions) Reset to builtin version or last successful bundle. ```typescript // Reset to builtin await updater.reset({ toLastSuccessful: false }); // Reset to last successful bundle await updater.reset({ toLastSuccessful: true }); ``` **Parameters:** | Option | Type | Required | Description | | ------------------ | ------- | -------- | ----------------------------------------------------------- | | `toLastSuccessful` | boolean | No | If true, reset to last successful bundle instead of builtin | ## Bundle Information [Section titled “Bundle Information”](#bundle-information) ### current() [Section titled “current()”](#current) Get information about the current bundle and native version. ```typescript const info = await updater.current(); // { bundle: { id, version, status }, native: '1.0.0' } ``` ### list(options) [Section titled “list(options)”](#listoptions) List all downloaded bundles. ```typescript const bundles = await updater.list(); // [{ id, version, status, downloaded, checksum }, ...] ``` ### getNextBundle() [Section titled “getNextBundle()”](#getnextbundle) Get the bundle queued for next restart. ```typescript const next = await updater.getNextBundle(); // { id, version, status } or null ``` ### getFailedUpdate() [Section titled “getFailedUpdate()”](#getfailedupdate) Get information about the last failed update (useful for debugging rollbacks). ```typescript const failed = await updater.getFailedUpdate(); // { id, version, reason } or null ``` ### getBuiltinVersion() [Section titled “getBuiltinVersion()”](#getbuiltinversion) Get the version shipped with the app binary. ```typescript const version = await updater.getBuiltinVersion(); // '1.0.0' ``` ## Update Checking [Section titled “Update Checking”](#update-checking) ### getLatest(options) [Section titled “getLatest(options)”](#getlatestoptions) Check the server for the latest available version. ```typescript const latest = await updater.getLatest(); if (latest.url && !latest.error) { // Update available console.log('New version:', latest.version); console.log('Download URL:', latest.url); } else if (latest.error) { console.error('Error checking updates:', latest.error); } ``` **Returns:** | Property | Type | Description | | ------------ | ------ | --------------------------------- | | `url` | string | Download URL (empty if no update) | | `version` | string | Available version | | `checksum` | string | SHA256 checksum | | `sessionKey` | string | Encryption session key | | `error` | string | Error message if check failed | | `message` | string | Server message | ## Channel Management [Section titled “Channel Management”](#channel-management) ### setChannel(options) [Section titled “setChannel(options)”](#setchanneloptions) Assign the device to a specific channel. ```typescript await updater.setChannel({ channel: 'beta' }); ``` ### unsetChannel(options) [Section titled “unsetChannel(options)”](#unsetchanneloptions) Remove channel assignment and use default. ```typescript await updater.unsetChannel(); ``` ### getChannel() [Section titled “getChannel()”](#getchannel) Get the current channel assignment. ```typescript const channel = await updater.getChannel(); // { channel: 'production', status: 'set' } ``` ### listChannels() [Section titled “listChannels()”](#listchannels) List all available channels for this app. ```typescript const channels = await updater.listChannels(); // ['production', 'beta', 'staging'] ``` ## Delay Conditions [Section titled “Delay Conditions”](#delay-conditions) Control when downloaded updates are applied. ### setMultiDelay(options) [Section titled “setMultiDelay(options)”](#setmultidelayoptions) Set conditions that must be met before an update is applied. ```typescript // Wait for app to be backgrounded await updater.setMultiDelay({ delayConditions: [{ kind: 'background' }] }); // Wait until specific date await updater.setMultiDelay({ delayConditions: [{ kind: 'date', value: '2024-12-25T00:00:00Z' }] }); // Wait for app to be killed and restarted await updater.setMultiDelay({ delayConditions: [{ kind: 'kill' }] }); // Multiple conditions (all must be met) await updater.setMultiDelay({ delayConditions: [ { kind: 'background' }, { kind: 'date', value: '2024-12-25T00:00:00Z' } ] }); ``` **Delay Condition Types:** | Kind | Value | Description | | --------------- | ---------------------- | --------------------------------------- | | `background` | Optional duration (ms) | Wait for app to be backgrounded | | `kill` | - | Wait for app to be killed and restarted | | `date` | ISO date string | Wait until specific date/time | | `nativeVersion` | Version string | Wait for native app update | ### cancelDelay() [Section titled “cancelDelay()”](#canceldelay) Clear all delay conditions and apply update immediately on next check. ```typescript await updater.cancelDelay(); ``` ## Device Identification [Section titled “Device Identification”](#device-identification) ### getDeviceId() [Section titled “getDeviceId()”](#getdeviceid) Get the unique device identifier. ```typescript const deviceId = await updater.getDeviceId(); // 'uuid-xxxx-xxxx-xxxx' ``` ### setCustomId(options) [Section titled “setCustomId(options)”](#setcustomidoptions) Set a custom identifier for the device (useful for analytics). ```typescript await updater.setCustomId({ customId: 'user-123' }); ``` ## Configuration [Section titled “Configuration”](#configuration) ### setUpdateUrl(options) [Section titled “setUpdateUrl(options)”](#setupdateurloptions) Change the update server URL at runtime. ```typescript await updater.setUpdateUrl({ url: 'https://my-server.com/updates' }); ``` Note Requires `allowModifyUrl: true` in the constructor options. ### setStatsUrl(options) [Section titled “setStatsUrl(options)”](#setstatsurloptions) Change the statistics reporting URL. ```typescript await updater.setStatsUrl({ url: 'https://my-server.com/stats' }); ``` ### setChannelUrl(options) [Section titled “setChannelUrl(options)”](#setchannelurloptions) Change the channel management URL. ```typescript await updater.setChannelUrl({ url: 'https://my-server.com/channel' }); ``` ### setAppId(options) [Section titled “setAppId(options)”](#setappidoptions) Change the App ID at runtime. ```typescript await updater.setAppId({ appId: 'com.example.newapp' }); ``` Note Requires `allowModifyAppId: true` in the constructor options. ### getAppId() [Section titled “getAppId()”](#getappid) Get the current App ID. ```typescript const appId = await updater.getAppId(); ``` ## Debug [Section titled “Debug”](#debug) ### setDebugMenu(options) [Section titled “setDebugMenu(options)”](#setdebugmenuoptions) Enable or disable the debug menu. ```typescript await updater.setDebugMenu({ enabled: true }); ``` ### isDebugMenuEnabled() [Section titled “isDebugMenuEnabled()”](#isdebugmenuenabled) Check if the debug menu is enabled. ```typescript const enabled = await updater.isDebugMenuEnabled(); ``` ## Events [Section titled “Events”](#events) Listen to update events using `addListener`: ```typescript updater.addListener('eventName', (event) => { // Handle event }); ``` ### Available Events [Section titled “Available Events”](#available-events) | Event | Payload | Description | | ------------------- | --------------------- | ------------------------------------------------------ | | `download` | `{ percent, status }` | Download progress updates | | `updateAvailable` | `{ bundle }` | New update available | | `noNeedUpdate` | `{ message }` | Already up-to-date | | `downloadComplete` | `{ bundle }` | Download finished successfully | | `downloadFailed` | `{ bundle, error }` | Download failed | | `breakingAvailable` | `{ bundle }` | Incompatible update available (requires native update) | | `updateFailed` | `{ bundle, reason }` | Update installation failed | | `appReloaded` | `{}` | App was reloaded | | `appReady` | `{}` | `notifyAppReady()` was called | ### Example: Full Event Handling [Section titled “Example: Full Event Handling”](#example-full-event-handling) ```typescript // Progress tracking updater.addListener('download', (event) => { updateProgressBar(event.percent); }); // Update available notification updater.addListener('updateAvailable', (event) => { showNotification(`Update ${event.bundle.version} available!`); }); // Handle completion updater.addListener('downloadComplete', async (event) => { // Queue for next restart await updater.next({ id: event.bundle.id }); showNotification('Update will apply on next restart'); }); // Handle failures updater.addListener('updateFailed', (event) => { console.error('Update failed:', event.reason); reportError(event); }); ``` ## Constructor Options [Section titled “Constructor Options”](#constructor-options) Full configuration options for `ElectronUpdater`: ```typescript const updater = new ElectronUpdater({ // Required appId: 'com.example.app', // Version override version: '1.0.0', // Override builtin version detection // Server URLs updateUrl: 'https://plugin.capgo.app/updates', channelUrl: 'https://plugin.capgo.app/channel_self', statsUrl: 'https://plugin.capgo.app/stats', // Behavior autoUpdate: true, // Enable automatic update checks appReadyTimeout: 10000, // Milliseconds before rollback (default: 10000) autoDeleteFailed: true, // Auto-delete failed bundles autoDeletePrevious: true, // Auto-delete old bundles resetWhenUpdate: true, // Reset to builtin on native update // Channels defaultChannel: 'production', // Direct Update Mode directUpdate: false, // 'atInstall' | 'onLaunch' | 'always' | false // Security publicKey: '...', // RSA public key for E2E encryption // Dynamic Configuration allowModifyUrl: false, // Allow runtime URL changes allowModifyAppId: false, // Allow runtime App ID changes persistCustomId: false, // Persist custom ID across updates persistModifyUrl: false, // Persist URL changes // Debug debugMenu: false, // Enable debug menu (Ctrl+Shift+D) disableJSLogging: false, // Disable console logs // Periodic Updates periodCheckDelay: 0, // Seconds between auto-checks (0 = disabled, min 600) }); ``` # Getting Started with Electron Updater > Complete setup guide for adding Capgo live updates to your Electron application. This guide walks you through setting up `@capgo/electron-updater` in your Electron application to enable live JavaScript/HTML/CSS updates. Tip Already using Capgo with Capacitor? The Electron Updater uses the same Capgo Cloud backend, so you can manage both mobile and desktop apps from the same dashboard. ## Prerequisites [Section titled “Prerequisites”](#prerequisites) * Electron 20.0.0 or higher * Node.js 18 or higher * A Capgo account (sign up at [capgo.app](https://capgo.app)) ## Installation [Section titled “Installation”](#installation) 1. Install the package: ```bash bun add @capgo/electron-updater ``` 2. Get your App ID from the Capgo dashboard. If you haven’t created an app yet, run: ```bash npx @capgo/cli@latest init ``` ## Setup [Section titled “Setup”](#setup) The Electron Updater requires setup in three places: main process, preload script, and renderer process. ### Main Process [Section titled “Main Process”](#main-process) main.ts ```typescript import { app, BrowserWindow } from 'electron'; import * as path from 'path'; import { ElectronUpdater, setupIPCHandlers, setupEventForwarding, } from '@capgo/electron-updater'; // Create updater instance with your Capgo App ID const updater = new ElectronUpdater({ appId: 'YOUR_CAPGO_APP_ID', // e.g., 'com.example.myapp' autoUpdate: true, }); app.whenReady().then(async () => { const mainWindow = new BrowserWindow({ width: 1200, height: 800, webPreferences: { preload: path.join(__dirname, 'preload.js'), contextIsolation: true, }, }); // Initialize updater with window and builtin path const builtinPath = path.join(__dirname, 'www/index.html'); await updater.initialize(mainWindow, builtinPath); // Setup IPC communication between main and renderer setupIPCHandlers(updater); setupEventForwarding(updater, mainWindow); // Load the current bundle (either builtin or downloaded update) await mainWindow.loadFile(updater.getCurrentBundlePath()); }); app.on('window-all-closed', () => { if (process.platform !== 'darwin') { app.quit(); } }); ``` ### Preload Script [Section titled “Preload Script”](#preload-script) preload.ts ```typescript import { exposeUpdaterAPI } from '@capgo/electron-updater/preload'; // Expose the updater API to the renderer process exposeUpdaterAPI(); ``` ### Renderer Process [Section titled “Renderer Process”](#renderer-process) ```typescript // renderer.ts (or in your app's entry point) import { requireUpdater } from '@capgo/electron-updater/renderer'; const updater = requireUpdater(); // CRITICAL: Call this on every app launch! // This confirms the bundle loaded successfully and prevents rollback await updater.notifyAppReady(); console.log('App ready, current bundle:', await updater.current()); ``` Caution You **must** call `notifyAppReady()` within 10 seconds of app launch (configurable via `appReadyTimeout`). If not called, the updater assumes the update failed and rolls back to the previous version. ## Checking for Updates [Section titled “Checking for Updates”](#checking-for-updates) With `autoUpdate: true`, the updater automatically checks for updates. You can also trigger manual checks: ```typescript // Check for updates manually const latest = await updater.getLatest(); if (latest.url && !latest.error) { console.log('Update available:', latest.version); // Download the update const bundle = await updater.download({ url: latest.url, version: latest.version, checksum: latest.checksum, }); console.log('Downloaded bundle:', bundle.id); // Option 1: Queue for next restart await updater.next({ id: bundle.id }); // Option 2: Apply immediately and reload // await updater.set({ id: bundle.id }); } ``` ## Listening to Events [Section titled “Listening to Events”](#listening-to-events) Track update progress and status with events: ```typescript // Download progress updater.addListener('download', (event) => { console.log(`Download progress: ${event.percent}%`); }); // Update available updater.addListener('updateAvailable', (event) => { console.log('New version available:', event.bundle.version); }); // Download completed updater.addListener('downloadComplete', (event) => { console.log('Download finished:', event.bundle.id); }); // Update failed updater.addListener('updateFailed', (event) => { console.error('Update failed:', event.bundle.version); }); ``` ## Deploying Updates [Section titled “Deploying Updates”](#deploying-updates) Use the Capgo CLI to upload updates: ```bash # Build your app npm run build # Upload to Capgo npx @capgo/cli@latest bundle upload --channel=production ``` Your Electron app will automatically detect and download the new bundle on next check. ## Debug Menu [Section titled “Debug Menu”](#debug-menu) Enable the debug menu during development: ```typescript const updater = new ElectronUpdater({ appId: 'YOUR_CAPGO_APP_ID', debugMenu: true, // Enable debug menu }); ``` Press `Ctrl+Shift+D` (or `Cmd+Shift+D` on Mac) to open the debug menu and: * View current bundle information * Switch between available bundles * Reset to builtin version * View device and channel info ## Configuration Options [Section titled “Configuration Options”](#configuration-options) ```typescript const updater = new ElectronUpdater({ // Required appId: 'com.example.app', // Server URLs (defaults to Capgo Cloud) updateUrl: 'https://plugin.capgo.app/updates', channelUrl: 'https://plugin.capgo.app/channel_self', statsUrl: 'https://plugin.capgo.app/stats', // Behavior autoUpdate: true, // Enable auto-updates appReadyTimeout: 10000, // MS before rollback (default: 10s) autoDeleteFailed: true, // Delete failed bundles autoDeletePrevious: true, // Delete old bundles after successful update // Channels defaultChannel: 'production', // Security publicKey: '...', // For end-to-end encryption // Debug debugMenu: false, // Enable debug menu disableJSLogging: false, // Disable console logs // Periodic Updates periodCheckDelay: 0, // Seconds between checks (0 = disabled, min 600) }); ``` ## Next Steps [Section titled “Next Steps”](#next-steps) * [API Reference](/docs/plugins/electron-updater/api/) - Explore all available methods * [Channels](/docs/live-updates/channels/) - Learn about deployment channels * [Rollbacks](/docs/live-updates/rollbacks/) - Understand rollback protection # @capgo/capacitor-env > Capacitor plugin for accessing environment variables in native code. ## Overview [Section titled “Overview”](#overview) Capacitor plugin for accessing environment variables in native code. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `getKey` - Retrieves the value of a specific environment variable by key. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------ | -------------------------------------------------------------- | | `getKey` | Retrieves the value of a specific environment variable by key. | | `getPluginVersion` | Get the version of the native Capacitor plugin. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-env](https://github.com/Cap-go/capacitor-env/). # Getting Started > Install @capgo/capacitor-env and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-env bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { Env } from '@capgo/capacitor-env'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `getKey` [Section titled “getKey”](#getkey) Retrieves the value of a specific environment variable by key. This method fetches environment variables that were set during the native build process. The variables must be configured in the native project before they can be accessed at runtime. ```typescript import { Env } from '@capgo/capacitor-env'; const result = await EnvPlugin.getKey({ key: 'API_URL' }); console.log(result.value); // 'https://api.example.com' ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-facebook-analytics > Log Meta/Facebook App Events, purchases, value-bearing standard events, and advertiser tracking status from Capacitor. ## Overview [Section titled “Overview”](#overview) `@capgo/capacitor-facebook-analytics` wraps Meta App Events for Capacitor apps on iOS and Android. Use it to log standard Facebook events, custom events, purchases, and value-bearing events with currency metadata. It also exposes advertiser tracking controls for Android and legacy iOS, while reporting App Tracking Transparency authorization on iOS 17 and above. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `initAppEvents` - Activate Facebook App Events manually when automatic app event logging is disabled. * `logEvent` - Log standard or custom App Events with optional parameters, value, and currency. * `logPurchase` - Log purchase events with amount, currency, and optional parameters. * `enableAdvertiserTracking` - Enable advertiser ID collection where the native SDK still supports explicit toggling. * `disableAdvertiserTracking` - Disable advertiser ID collection where the native SDK still supports explicit toggling. * `getAdvertiserTrackingStatus` - Read the current advertiser tracking status. ## Platform Support [Section titled “Platform Support”](#platform-support) | Platform | Support | | -------- | ---------------- | | iOS | Supported | | Android | Supported | | Web | Unsupported stub | ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ----------------------------- | ------------------------------------------- | | `initAppEvents` | Activate Facebook App Events. | | `logEvent` | Log a Facebook App Event. | | `logPurchase` | Log a Facebook purchase event. | | `enableAdvertiserTracking` | Enable advertiser tracking. | | `disableAdvertiserTracking` | Disable advertiser tracking. | | `getAdvertiserTrackingStatus` | Get the current advertiser tracking status. | | `getPluginVersion` | Return the native plugin version marker. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-facebook-analytics](https://github.com/Cap-go/capacitor-facebook-analytics/). # Getting Started > Install @capgo/capacitor-facebook-analytics and log Meta/Facebook App Events from Capacitor. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-facebook-analytics bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { FacebookAnalytics, FacebookEventName, FacebookEventParameterName, } from '@capgo/capacitor-facebook-analytics'; ``` ## Native Setup [Section titled “Native Setup”](#native-setup) Configure your Meta app id and client token in the native app. The plugin does not create these values for you. ### iOS [Section titled “iOS”](#ios) Add your Meta values to `Info.plist`: ```xml FacebookAppID YOUR_FACEBOOK_APP_ID FacebookClientToken YOUR_FACEBOOK_CLIENT_TOKEN FacebookDisplayName YOUR_APP_NAME ``` ### Android [Section titled “Android”](#android) Add your Meta values to `AndroidManifest.xml`: ```xml ``` Add the string resources in `android/app/src/main/res/values/strings.xml`: ```xml YOUR_FACEBOOK_APP_ID YOUR_FACEBOOK_CLIENT_TOKEN ``` ## Enable Advertiser Tracking [Section titled “Enable Advertiser Tracking”](#enable-advertiser-tracking) Call this after your consent flow allows tracking. ```typescript await FacebookAnalytics.enableAdvertiserTracking(); ``` On iOS 17 and above, FBSDK v17+ reads App Tracking Transparency directly. Use your app’s ATT flow before logging tracking-dependent events. ## Log A Standard Event [Section titled “Log A Standard Event”](#log-a-standard-event) ```typescript await FacebookAnalytics.logEvent({ event: FacebookEventName.CompletedRegistration, params: { [FacebookEventParameterName.RegistrationMethod]: 'email', }, }); ``` ## Log A Value Event With Currency [Section titled “Log A Value Event With Currency”](#log-a-value-event-with-currency) ```typescript await FacebookAnalytics.logEvent({ event: FacebookEventName.AddedToCart, valueToSum: 19.99, currency: 'USD', params: { [FacebookEventParameterName.ContentType]: 'product', [FacebookEventParameterName.ContentId]: 'sku-123', }, }); ``` ## Log A Purchase [Section titled “Log A Purchase”](#log-a-purchase) ```typescript await FacebookAnalytics.logPurchase({ amount: 9.99, currency: 'USD', }); ``` ## Read Tracking Status [Section titled “Read Tracking Status”](#read-tracking-status) ```typescript const { status } = await FacebookAnalytics.getAdvertiserTrackingStatus(); console.log('Advertiser tracking enabled:', status); ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-fast-sql > Fast SQL Plugin for high-performance SQLite database access. ## Overview [Section titled “Overview”](#overview) Fast SQL Plugin for high-performance SQLite database access. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `connect` - Initialize the database connection and start the HTTP server. * `disconnect` - Close database connection and stop the HTTP server. * `getServerInfo` - Get the HTTP server port and token for direct communication. * `execute` - Execute a SQL query via Capacitor bridge (for simple queries). For better performance with large datasets, use the HTTP protocol directly via SQLConnection class. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `connect` | Initialize the database connection and start the HTTP server. | | `disconnect` | Close database connection and stop the HTTP server. | | `getServerInfo` | Get the HTTP server port and token for direct communication. | | `execute` | Execute a SQL query via Capacitor bridge (for simple queries). For better performance with large datasets, use the HTTP protocol directly via SQLConnection class. | | `beginTransaction` | Begin a database transaction. | | `commitTransaction` | Commit the current transaction. | | `rollbackTransaction` | Rollback the current transaction. | | `getPluginVersion` | Get the native Capacitor plugin version. | | `configureWeb` | Configure web-specific options for the sql.js WASM module. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-fast-sql](https://github.com/Cap-go/capacitor-fast-sql/). # Getting Started > Install @capgo/capacitor-fast-sql and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-fast-sql bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { CapgoCapacitorFastSql } from '@capgo/capacitor-fast-sql'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `connect` [Section titled “connect”](#connect) Initialize the database connection and start the HTTP server. ```typescript import { CapgoCapacitorFastSql } from '@capgo/capacitor-fast-sql'; const conn = await CapgoCapacitorFastSql.connect({ database: 'myapp' }); console.log('Connected on port:', conn.port); ``` ### `disconnect` [Section titled “disconnect”](#disconnect) Close database connection and stop the HTTP server. ```typescript import { CapgoCapacitorFastSql } from '@capgo/capacitor-fast-sql'; await CapgoCapacitorFastSql.disconnect({ database: 'myapp' }); ``` ### `getServerInfo` [Section titled “getServerInfo”](#getserverinfo) Get the HTTP server port and token for direct communication. ```typescript import { CapgoCapacitorFastSql } from '@capgo/capacitor-fast-sql'; const info = await CapgoCapacitorFastSql.getServerInfo({ database: 'myapp' }); console.log('Server port:', info.port); ``` ### `execute` [Section titled “execute”](#execute) Execute a SQL query via Capacitor bridge (for simple queries). For better performance with large datasets, use the HTTP protocol directly via SQLConnection class. ```typescript import { CapgoCapacitorFastSql } from '@capgo/capacitor-fast-sql'; const result = await CapgoCapacitorFastSql.execute({ database: 'myapp', statement: 'SELECT * FROM users WHERE age > ?', params: [18] }); console.log('Rows:', result.rows); ``` ### `beginTransaction` [Section titled “beginTransaction”](#begintransaction) Begin a database transaction. ```typescript import { CapgoCapacitorFastSql } from '@capgo/capacitor-fast-sql'; await CapgoCapacitorFastSql.beginTransaction({ database: 'myapp' }); // Execute multiple operations await CapgoCapacitorFastSql.commitTransaction({ database: 'myapp' }); ``` ### `commitTransaction` [Section titled “commitTransaction”](#committransaction) Commit the current transaction. ```typescript import { CapgoCapacitorFastSql } from '@capgo/capacitor-fast-sql'; await CapgoCapacitorFastSql.commitTransaction({ database: 'myapp' }); ``` ### `rollbackTransaction` [Section titled “rollbackTransaction”](#rollbacktransaction) Rollback the current transaction. ```typescript import { CapgoCapacitorFastSql } from '@capgo/capacitor-fast-sql'; try { await CapgoCapacitorFastSql.beginTransaction({ database: 'myapp' }); // Operations... await CapgoCapacitorFastSql.commitTransaction({ database: 'myapp' }); } catch (error) { await CapgoCapacitorFastSql.rollbackTransaction({ database: 'myapp' }); } ``` ### `configureWeb` [Section titled “configureWeb”](#configureweb) Configure web-specific options for the sql.js WASM module. Call this **before** the first `connect()` call to load sql.js from a locally bundled path instead of the default CDN. This method is a no-op on iOS and Android. ```typescript import { CapgoCapacitorFastSql } from '@capgo/capacitor-fast-sql'; // Configure once at app startup (web only) await CapgoCapacitorFastSql.configureWeb({ sqlJsUrl: '/assets/sql-wasm.js', wasmUrl: '/assets/sql-wasm.wasm', }); const db = await FastSQL.connect({ database: 'myapp' }); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `SQLConnectionOptions` [Section titled “SQLConnectionOptions”](#sqlconnectionoptions) Database connection options. ```typescript export interface SQLConnectionOptions { /** * Database name (file will be created in app data directory) */ database: string; /** * Enable encryption (iOS/Android only) */ encrypted?: boolean; /** * Encryption key (required if encrypted is true) */ encryptionKey?: string; /** * Read-only mode */ readOnly?: boolean; } ``` ### `SQLValue` [Section titled “SQLValue”](#sqlvalue) SQL value types supported by the plugin. ```typescript export type SQLValue = string | number | boolean | null | Uint8Array; ``` ### `SQLResult` [Section titled “SQLResult”](#sqlresult) Result of a SQL query execution. ```typescript export interface SQLResult { /** * Rows returned by the query (for SELECT statements) */ rows: SQLRow[]; /** * Number of rows affected by the query (for INSERT/UPDATE/DELETE) */ rowsAffected: number; /** * ID of the last inserted row (for INSERT statements with auto-increment) */ insertId?: number; } ``` ### `IsolationLevel` [Section titled “IsolationLevel”](#isolationlevel) Transaction isolation levels. ```typescript export enum IsolationLevel { ReadUncommitted = 'READ UNCOMMITTED', ReadCommitted = 'READ COMMITTED', RepeatableRead = 'REPEATABLE READ', Serializable = 'SERIALIZABLE', } ``` ### `WebConfig` [Section titled “WebConfig”](#webconfig) Web platform configuration for the sql.js WASM module. Use with `configureWeb()` to load sql.js from a locally bundled path instead of the default CDN. ```typescript export interface WebConfig { /** * URL to the sql.js JavaScript file (`sql-wasm.js`). * When omitted, the plugin loads from the cdnjs CDN. * @example '/assets/sql-wasm.js' */ sqlJsUrl?: string; /** * URL to the sql.js WebAssembly binary (`sql-wasm.wasm`). * When omitted, the plugin loads from the cdnjs CDN. * @example '/assets/sql-wasm.wasm' */ wasmUrl?: string; } ``` ### `SQLRow` [Section titled “SQLRow”](#sqlrow) SQL row result - values indexed by column name. ```typescript export interface SQLRow { [column: string]: SQLValue; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-ffmpeg > Exposes the FFmpeg API to Capacitor. ## Overview [Section titled “Overview”](#overview) Exposes the FFmpeg API to Capacitor. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `getCapabilities` - Return the machine-readable capability matrix for the current platform. * `reencodeVideo` - Queue a video re-encode job. * `convertImage` - Convert a still image into another format. * `convertAudio` - Convert audio into another container or codec. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------ | ------------------------------------------------------------------------------- | | `getCapabilities` | Return the machine-readable capability matrix for the current platform. | | `reencodeVideo` | Queue a video re-encode job. | | `convertImage` | Convert a still image into another format. | | `convertAudio` | Convert audio into another container or codec. | | `addListener` | Listen for media job progress. | | `getPluginVersion` | Get the plugin package version reported by the current platform implementation. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-ffmpeg](https://github.com/Cap-go/capacitor-ffmpeg/). # Getting Started > Install @capgo/capacitor-ffmpeg and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-ffmpeg bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { CapacitorFFmpeg } from '@capgo/capacitor-ffmpeg'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `getCapabilities` [Section titled “getCapabilities”](#getcapabilities) Return the machine-readable capability matrix for the current platform. ```typescript import { CapacitorFFmpeg } from '@capgo/capacitor-ffmpeg'; await CapacitorFFmpeg.getCapabilities(); ``` ### `reencodeVideo` [Section titled “reencodeVideo”](#reencodevideo) Queue a video re-encode job. On iOS, the returned promise resolves when the native layer accepts the job. Final success or failure is delivered through the `progress` listener. Android and web currently reject with `UNIMPLEMENTED`. ```typescript import { CapacitorFFmpeg } from '@capgo/capacitor-ffmpeg'; await CapacitorFFmpeg.reencodeVideo({} as ReencodeVideoOptions); ``` ### `convertImage` [Section titled “convertImage”](#convertimage) Convert a still image into another format. iOS currently supports `jpeg` and `.png`. Android currently supports `.webp`, `jpeg`, and `.png`. Web currently rejects with `UNIMPLEMENTED`. ```typescript import { CapacitorFFmpeg } from '@capgo/capacitor-ffmpeg'; await CapacitorFFmpeg.convertImage({} as ConvertImageOptions); ``` ### `convertAudio` [Section titled “convertAudio”](#convertaudio) Convert audio into another container or codec. iOS currently supports `m4a`. Android and web currently reject with `UNIMPLEMENTED`. ```typescript import { CapacitorFFmpeg } from '@capgo/capacitor-ffmpeg'; await CapacitorFFmpeg.convertAudio({} as ConvertAudioOptions); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `FFmpegCapabilitiesResult` [Section titled “FFmpegCapabilitiesResult”](#ffmpegcapabilitiesresult) ```typescript export interface FFmpegCapabilitiesResult { platform: string; features: FFmpegCapabilitiesFeatures; } ``` ### `ReencodeVideoOptions` [Section titled “ReencodeVideoOptions”](#reencodevideooptions) ```typescript export interface ReencodeVideoOptions { inputPath: string; outputPath: string; width: number; height: number; bitrate?: number; } ``` ### `FFmpegAcceptedJob` [Section titled “FFmpegAcceptedJob”](#ffmpegacceptedjob) ```typescript export interface FFmpegAcceptedJob { jobId: string; status: 'queued'; } ``` ### `ConvertImageOptions` [Section titled “ConvertImageOptions”](#convertimageoptions) ```typescript export interface ConvertImageOptions { inputPath: string; outputPath: string; format: ImageOutputFormat; /** * Compression quality in the inclusive range `0.0..1.0`. * * Native platforms reject values outside that range. */ quality?: number; } ``` ### `ConvertImageResult` [Section titled “ConvertImageResult”](#convertimageresult) ```typescript export interface ConvertImageResult { outputPath: string; format: ImageOutputFormat; } ``` ### `ConvertAudioOptions` [Section titled “ConvertAudioOptions”](#convertaudiooptions) ```typescript export interface ConvertAudioOptions { inputPath: string; outputPath: string; format: AudioOutputFormat; } ``` ### `ConvertAudioResult` [Section titled “ConvertAudioResult”](#convertaudioresult) ```typescript export interface ConvertAudioResult { outputPath: string; format: AudioOutputFormat; } ``` ### `FFmpegProgressEvent` [Section titled “FFmpegProgressEvent”](#ffmpegprogressevent) ```typescript export interface FFmpegProgressEvent { jobId: string; /** * Normalized progress as a floating-point value in the inclusive range `0.0..1.0`. */ progress: number; state: FFmpegProgressState; message?: string; outputPath?: string; /** * Legacy alias kept for compatibility while callers migrate to `jobId`. */ fileId?: string; } ``` ### `PluginVersionResult` [Section titled “PluginVersionResult”](#pluginversionresult) ```typescript export interface PluginVersionResult { version: string; } ``` ### `FFmpegCapabilitiesFeatures` [Section titled “FFmpegCapabilitiesFeatures”](#ffmpegcapabilitiesfeatures) ```typescript export interface FFmpegCapabilitiesFeatures { getPluginVersion: FFmpegCapability; getCapabilities: FFmpegCapability; reencodeVideo: FFmpegCapability; convertImage: FFmpegCapability; convertAudio?: FFmpegCapability; progressEvents: FFmpegCapability; probeMedia: FFmpegCapability; generateThumbnail: FFmpegCapability; extractAudio: FFmpegCapability; remux: FFmpegCapability; trim: FFmpegCapability; } ``` ### `ImageOutputFormat` [Section titled “ImageOutputFormat”](#imageoutputformat) ```typescript export type ImageOutputFormat = '.webp' | 'jpeg' | '.png'; ``` ### `AudioOutputFormat` [Section titled “AudioOutputFormat”](#audiooutputformat) ```typescript export type AudioOutputFormat = 'm4a'; ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-file > Capacitor File Plugin Implements file system operations similar to the Cordova File plugin. ## Overview [Section titled “Overview”](#overview) Capacitor File Plugin Implements file system operations similar to the Cordova File plugin. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `requestFileSystem` - Request a file system. * `resolveLocalFileSystemURL` - Resolve a file URL to an entry. * `getFile` - Get a file entry. * `getDirectory` - Get a directory entry. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `requestFileSystem` | Request a file system. | | `resolveLocalFileSystemURL` | Resolve a file URL to an entry. | | `getFile` | Get a file entry. | | `getDirectory` | Get a directory entry. | | `readFile` | Read a file as text or base64. | | `readAsDataURL` | Read a file as a data URL (base64 with MIME type prefix). | | `writeFile` | Write data to a file. | | `appendFile` | Append data to a file. | | `deleteFile` | Delete a file. | | `mkdir` | Create a directory. | | `rmdir` | Delete a directory. | | `readdir` | Read directory contents. | | `stat` | Get metadata about a file or directory. | | `getMetadata` | Get metadata about a file or directory. Alias for stat(). | | `rename` | Rename or move a file or directory. | | `move` | Move a file or directory. Alias for rename(). | | `copy` | Copy a file or directory. | | `exists` | Check if a file or directory exists. | | `getUri` | Get the URI for a file. | | `truncate` | Truncate a file to a specified size. | | `getDirectories` | Get all known file system directories. | | `getFreeDiskSpace` | Get the free disk space in bytes. | | `addListener` | Listen for read progress events. | | `addListener` | Listen for write progress events. | | `removeAllListeners` | Remove all event listeners. | | `getPluginVersion` | Get the plugin version. | | `checkPermissions` | Check the current permission status for file operations. On Android, this checks for external storage permissions. On iOS and web, this always returns ‘granted’ as no special permissions are needed. | | `requestPermissions` | Request permissions for file operations. On Android, this requests external storage permissions needed for accessing files outside the app’s private directories. On iOS and web, this always returns ‘granted’ as no special permissions are needed. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-file](https://github.com/Cap-go/capacitor-file/). # @capgo/capacitor-file-compressor > Capacitor File Compressor Plugin interface for image compression. ## Overview [Section titled “Overview”](#overview) Capacitor File Compressor Plugin interface for image compression. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `compressImage` - Compresses an image file with specified dimensions and quality settings. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------ | ------------------------------------------------------------------------ | | `compressImage` | Compresses an image file with specified dimensions and quality settings. | | `getPluginVersion` | Get the native Capacitor plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-file-compressor](https://github.com/Cap-go/capacitor-file-compressor/). # Getting Started > Install @capgo/capacitor-file-compressor and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-file-compressor bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { FileCompressor } from '@capgo/capacitor-file-compressor'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `compressImage` [Section titled “compressImage”](#compressimage) Compresses an image file with specified dimensions and quality settings. This method compresses images to reduce file size while maintaining acceptable quality. It supports resizing and format conversion (JPEG/WebP depending on platform). **Important Notes:** * EXIF metadata is removed during compression on all platforms * Aspect ratio is automatically maintained if only one dimension is provided * Compressed files are saved to temporary directories on native platforms ```typescript import { FileCompressor } from '@capgo/capacitor-file-compressor'; // Web - Compress from file input const fileInput = document.getElementById('file') as HTMLInputElement; const file = fileInput.files[0]; const result = await FileCompressor.compressImage({ blob: file, quality: 0.8, width: 1200, mimeType: 'image/jpeg' }); const url = URL.createObjectURL(result.blob); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `CompressImageOptions` [Section titled “CompressImageOptions”](#compressimageoptions) Options for compressing an image. ````typescript export interface CompressImageOptions { /** * The file path of the image to compress. * * **Platform:** Android, iOS only (not supported on Web) * * Accepts various path formats: * - iOS: `file://` URLs or absolute paths * - Android: `content://` URIs, `file://` URLs, or absolute paths * * @since 7.0.0 * @example "file:///var/mobile/Containers/Data/Application/image.jpg" // iOS * @example "content://com.android.providers.downloads.documents/document/msf%3A1000000485" // Android * @example "/storage/emulated/0/Download/photo.png" // Android absolute path */ path?: string; /** * The file blob of the image to compress. * * **Platform:** Web only (not supported on iOS/Android) * * Use this when compressing images from file inputs, fetch responses, * or any other Blob source in web applications. * * @since 7.0.0 * @example * ```typescript * // From file input * const fileInput = document.getElementById('file') as HTMLInputElement; * const blob = fileInput.files[0]; * ``` * @example * ```typescript * // From fetch * const response = await fetch('https://example.com/image.jpg'); * const blob = await response.blob(); * ``` */ blob?: Blob; /** * The quality of the compressed image. * * **Range:** 0.0 to 1.0 * - `0.0` = Maximum compression (lowest quality, smallest file) * - `1.0` = Minimum compression (highest quality, largest file) * - `0.6` = Default balanced compression * * **Platform:** All platforms * * Higher quality values result in larger files but better visual quality. * The actual compression ratio depends on the image content and format. * * @since 7.0.0 * @default 0.6 * @example 0.8 // High quality * @example 0.5 // Medium quality, smaller file * @example 0.3 // Low quality, very small file */ quality?: number; /** * The width of the compressed image in pixels. * * **Platform:** All platforms * * If only width is specified, height is calculated automatically * to maintain the original aspect ratio. * * If both width and height are specified, the image is resized * to exact dimensions (may distort if ratio differs). * * @since 7.0.0 * @example 1920 // Full HD width * @example 1200 // Common web image width * @example 800 // Mobile-optimized width */ width?: number; /** * The height of the compressed image in pixels. * * **Platform:** All platforms * * If only height is specified, width is calculated automatically * to maintain the original aspect ratio. * * If both width and height are specified, the image is resized * to exact dimensions (may distort if ratio differs). * * @since 7.0.0 * @example 1080 // Full HD height * @example 800 // Common web image height * @example 600 // Mobile-optimized height */ height?: number; /** * The MIME type of the compressed output image. * * **Platform Support:** * - **iOS:** `image/jpeg` only * - **Android:** `image/jpeg`, `image/.webp` * - **Web:** `image/jpeg`, `image/.webp` * * **Format Characteristics:** * - **JPEG:** Universal support, good for photos, no transparency * - **WebP:** Better compression, supports transparency, not on iOS * * @since 7.0.0 * @default "image/jpeg" * @example "image/jpeg" // JPEG format (all platforms) * @example "image/.webp" // WebP format (Android/Web only) */ mimeType?: string; } ```` ### `CompressImageResult` [Section titled “CompressImageResult”](#compressimageresult) The result of compressing an image. ````typescript export interface CompressImageResult { /** * The file path of the compressed image. * * **Platform:** Android, iOS only (undefined on Web) * * Points to a temporary file containing the compressed image. * On iOS, typically in `NSTemporaryDirectory()`. * On Android, typically in app cache directory. * * **Important:** These files may be cleaned up by the OS. * Copy to permanent storage if needed for long-term use. * * @since 7.0.0 * @example "/var/mobile/Containers/Data/tmp/compressed_abc123.jpg" // iOS * @example "/data/user/0/com.app/cache/compressed_xyz789.jpg" // Android */ path?: string; /** * The blob of the compressed image. * * **Platform:** Web only (undefined on iOS/Android) * * A Blob object containing the compressed image data. * Can be used to: * - Create object URLs for preview: `URL.createObjectURL(blob)` * - Upload to server via FormData * - Save to IndexedDB or other storage * - Convert to base64 with FileReader * * @since 7.0.0 * @example * ```typescript * // Create preview URL * const url = URL.createObjectURL(result.blob); * imageElement.src = url; * ``` * @example * ```typescript * // Upload to server * const formData = new FormData(); * formData.append('image', result.blob, 'compressed.jpg'); * await fetch('/upload', { method: 'POST', body: formData }); * ``` */ blob?: Blob; } ```` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-file-picker > Capacitor File Picker Plugin interface for selecting files, images, videos, and directories. ## Overview [Section titled “Overview”](#overview) Capacitor File Picker Plugin interface for selecting files, images, videos, and directories. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `pickFiles` - Pick one or more files from the device. * `pickImages` - Pick one or more images from the gallery. Android/iOS only. * `pickVideos` - Pick one or more videos from the gallery. Android/iOS only. * `pickMedia` - Pick one or more images or videos from the gallery. Android/iOS only. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | -------------------- | --------------------------------------------------------------------- | | `pickFiles` | Pick one or more files from the device. | | `pickImages` | Pick one or more images from the gallery. Android/iOS only. | | `pickVideos` | Pick one or more videos from the gallery. Android/iOS only. | | `pickMedia` | Pick one or more images or videos from the gallery. Android/iOS only. | | `pickDirectory` | Pick a directory from the device. Android/iOS only. | | `convertHeicToJpeg` | Convert a HEIC image to JPEG format. iOS only. | | `copyFile` | Copy a file to a new location. | | `checkPermissions` | Check permissions for reading files. Android only. | | `requestPermissions` | Request permissions for reading files. Android only. | | `addListener` | Add a listener for the picker dismissed event. iOS only. | | `removeAllListeners` | Remove all listeners for this plugin. | | `getPluginVersion` | Get the native Capacitor plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-file-picker](https://github.com/Cap-go/capacitor-file-picker/). # Getting Started > Install @capgo/capacitor-file-picker and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-file-picker bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { CapgoFilePicker } from '@capgo/capacitor-file-picker'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `pickFiles` [Section titled “pickFiles”](#pickfiles) Pick one or more files from the device. ```typescript import { CapgoFilePicker } from '@capgo/capacitor-file-picker'; const result = await CapgoFilePicker.pickFiles({ types: ['application/pdf', 'image/*'], limit: 5, readData: false }); console.log('Picked files:', result.files); ``` ### `pickImages` [Section titled “pickImages”](#pickimages) Pick one or more images from the gallery. Android/iOS only. ```typescript import { CapgoFilePicker } from '@capgo/capacitor-file-picker'; const result = await CapgoFilePicker.pickImages({ limit: 10, readData: false }); console.log('Picked images:', result.files); ``` ### `pickVideos` [Section titled “pickVideos”](#pickvideos) Pick one or more videos from the gallery. Android/iOS only. ```typescript import { CapgoFilePicker } from '@capgo/capacitor-file-picker'; const result = await CapgoFilePicker.pickVideos({ limit: 3, skipTranscoding: true }); console.log('Picked videos:', result.files); ``` ### `pickMedia` [Section titled “pickMedia”](#pickmedia) Pick one or more images or videos from the gallery. Android/iOS only. ```typescript import { CapgoFilePicker } from '@capgo/capacitor-file-picker'; const result = await CapgoFilePicker.pickMedia({ limit: 5, readData: true }); console.log('Picked media:', result.files); ``` ### `pickDirectory` [Section titled “pickDirectory”](#pickdirectory) Pick a directory from the device. Android/iOS only. ```typescript import { CapgoFilePicker } from '@capgo/capacitor-file-picker'; const result = await CapgoFilePicker.pickDirectory(); console.log('Selected directory:', result.path); ``` ### `convertHeicToJpeg` [Section titled “convertHeicToJpeg”](#convertheictojpeg) Convert a HEIC image to JPEG format. iOS only. ```typescript import { CapgoFilePicker } from '@capgo/capacitor-file-picker'; const result = await CapgoFilePicker.convertHeicToJpeg({ path: '/path/to/image.heic', quality: 0.9 }); console.log('Converted file:', result.path); ``` ### `copyFile` [Section titled “copyFile”](#copyfile) Copy a file to a new location. ```typescript import { CapgoFilePicker } from '@capgo/capacitor-file-picker'; await CapgoFilePicker.copyFile({ from: '/source/file.pdf', to: '/destination/file.pdf', overwrite: true }); ``` ### `checkPermissions` [Section titled “checkPermissions”](#checkpermissions) Check permissions for reading files. Android only. ```typescript import { CapgoFilePicker } from '@capgo/capacitor-file-picker'; const status = await CapgoFilePicker.checkPermissions(); console.log('Read permission:', status.readExternalStorage); ``` ### `requestPermissions` [Section titled “requestPermissions”](#requestpermissions) Request permissions for reading files. Android only. ```typescript import { CapgoFilePicker } from '@capgo/capacitor-file-picker'; const status = await CapgoFilePicker.requestPermissions(); if (status.readExternalStorage === 'granted') { console.log('Permission granted'); } ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `PickFilesOptions` [Section titled “PickFilesOptions”](#pickfilesoptions) Options for picking files. ```typescript export interface PickFilesOptions { /** * List of accepted MIME types or file extensions. * On iOS, only MIME types are supported. * Examples: ['image/*'], ['application/pdf'], ['.pdf', '.doc'] */ types?: string[]; /** * Maximum number of files to pick. * Set to 0 for unlimited (platform default). * @default 0 */ limit?: number; /** * Whether to read the file data as base64. * Note: Reading large files may cause memory issues. * @default false */ readData?: boolean; } ``` ### `PickFilesResult` [Section titled “PickFilesResult”](#pickfilesresult) Result of picking files. ```typescript export interface PickFilesResult { /** Array of picked files */ files: PickedFile[]; } ``` ### `PickMediaOptions` [Section titled “PickMediaOptions”](#pickmediaoptions) Options for picking media (images/videos). ```typescript export interface PickMediaOptions { /** * Maximum number of files to pick. * Set to 0 for unlimited (platform default). * @default 0 */ limit?: number; /** * Whether to read the file data as base64. * Note: Reading large files may cause memory issues. * @default false */ readData?: boolean; /** * iOS only: Skip transcoding of videos. * @default false */ skipTranscoding?: boolean; /** * iOS 15+ only: Show ordered selection badges. * @default false */ ordered?: boolean; } ``` ### `PickDirectoryResult` [Section titled “PickDirectoryResult”](#pickdirectoryresult) Result of picking a directory. ```typescript export interface PickDirectoryResult { /** The path to the selected directory */ path: string; } ``` ### `ConvertHeicToJpegOptions` [Section titled “ConvertHeicToJpegOptions”](#convertheictojpegoptions) Options for converting HEIC to JPEG. ```typescript export interface ConvertHeicToJpegOptions { /** The path to the HEIC file to convert */ path: string; /** * The compression quality for JPEG (0.0 - 1.0). * @default 0.9 */ quality?: number; } ``` ### `ConvertHeicToJpegResult` [Section titled “ConvertHeicToJpegResult”](#convertheictojpegresult) Result of HEIC to JPEG conversion. ```typescript export interface ConvertHeicToJpegResult { /** The path to the converted JPEG file */ path: string; } ``` ### `CopyFileOptions` [Section titled “CopyFileOptions”](#copyfileoptions) Options for copying a file. ```typescript export interface CopyFileOptions { /** Source file path */ from: string; /** Destination file path */ to: string; /** * Whether to overwrite if destination exists. * @default false */ overwrite?: boolean; } ``` ### `PermissionStatus` [Section titled “PermissionStatus”](#permissionstatus) Permission status for file access. ```typescript export interface PermissionStatus { /** Whether permission to read media files is granted */ readExternalStorage: PermissionState; /** Whether permission to access media location is granted */ accessMediaLocation?: PermissionState; } ``` ### `PickerDismissedListener` [Section titled “PickerDismissedListener”](#pickerdismissedlistener) Listener callback for picker dismissed event. ```typescript export type PickerDismissedListener = (event: null) => void; ``` ### `PickedFile` [Section titled “PickedFile”](#pickedfile) Represents a picked file. ```typescript export interface PickedFile { /** The name of the file */ name: string; /** The path to the file */ path?: string; /** The MIME type of the file */ mimeType: string; /** The size of the file in bytes */ size: number; /** * The base64 encoded data of the file. * Only present if readData was true. */ data?: string; /** * The Blob instance of the file. * Web only. */ blob?: Blob; /** Width in pixels (images/videos only) */ width?: number; /** Height in pixels (images/videos only) */ height?: number; /** Duration in seconds (videos only) */ duration?: number; /** Last modified timestamp in milliseconds */ modifiedAt?: number; } ``` ### `PermissionState` [Section titled “PermissionState”](#permissionstate) Permission state values. ```typescript export type PermissionState = 'prompt' | 'prompt-with-rationale' | 'granted' | 'denied'; ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-file-sharer > Share and save files with native sheets, Android MediaStore, and browser downloads. ## Overview [Section titled “Overview”](#overview) `@capgo/capacitor-file-sharer` shares or saves files from base64 data, data URLs, local file paths, `file://` URLs, `content://` URIs, and Capacitor `_capacitor_file_` URLs. Use it when an app needs to export reports, backups, images, videos, PDFs, ZIP archives, or other generated files without forcing every platform through the same storage path. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `share` - Open the native share sheet on Android and iOS, or download the file on Web. * `save` - Save into Android public collections, open the iOS save/share sheet, or download on Web. * `getPluginVersion` - Return the native/web plugin implementation version. ## Platform Behavior [Section titled “Platform Behavior”](#platform-behavior) | Platform | Share behavior | Save behavior | | -------- | ------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | | Android | Uses a `FileProvider`, `ClipData`, and URI grants so chooser previews and thumbnails can read the file. | Uses MediaStore on Android 10+ and public directories on Android 9 and below. | | iOS | Uses `UIActivityViewController` with base64 or direct path-backed files. | Opens the native share sheet so the user can choose Save to Files or another destination. | | Web | Downloads the file. | Downloads the file. | ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------ | --------------------------------------------------------------------------------- | | `share` | Share a file using the native share sheet on Android and iOS, or download on Web. | | `save` | Save a file locally on Android/Web, or open the iOS save/share sheet. | | `getPluginVersion` | Returns the platform implementation version marker. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-file-sharer](https://github.com/Cap-go/capacitor-file-sharer/). # Getting Started > Install @capgo/capacitor-file-sharer and share or save files from base64 data and local paths. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-file-sharer bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { FileSharer } from '@capgo/capacitor-file-sharer'; ``` ## Share A Base64 File [Section titled “Share A Base64 File”](#share-a-base64-file) ```typescript import { FileSharer } from '@capgo/capacitor-file-sharer'; await FileSharer.share({ filename: 'report.pdf', contentType: 'application/pdf', base64Data: reportBase64, title: 'Quarterly report', text: 'Attached report', }); ``` `base64Data` can be a raw base64 string or a data URL such as `data:application/pdf;base64,...`. ## Share A Local File [Section titled “Share A Local File”](#share-a-local-file) ```typescript await FileSharer.share({ filename: 'export.zip', contentType: 'application/zip', path: fileUri, }); ``` The native implementations accept local paths, `file://` URLs, Android `content://` URIs, and Capacitor `_capacitor_file_` URLs. ## Save A File [Section titled “Save A File”](#save-a-file) ```typescript const result = await FileSharer.save({ filename: 'backup.zip', contentType: 'application/zip', base64Data: zipBase64, android: { saveDirectory: 'downloads', relativePath: 'Download/My App', }, }); console.log(result.uri); ``` Android save directories are `downloads`, `pictures`, `movies`, `music`, and `documents`. On Android 10 and newer, the plugin writes through MediaStore. On Android 9 and below, public saves use the manifest `WRITE_EXTERNAL_STORAGE` permission with `maxSdkVersion=28`. ## Share Text With A File [Section titled “Share Text With A File”](#share-text-with-a-file) ```typescript await FileSharer.share({ filename: 'photo.jpg', contentType: 'image/jpeg', path: photoUri, title: 'Site photo', subject: 'Photo export', text: 'Captured during inspection.', }); ``` `text` is passed as `EXTRA_TEXT` on Android and as a second activity item on iOS. ## Type Reference [Section titled “Type Reference”](#type-reference) ### `ShareFileOptions` [Section titled “ShareFileOptions”](#sharefileoptions) ```typescript export interface ShareFileOptions { filename: string; base64Data?: string; path?: string; contentType?: string; text?: string; title?: string; subject?: string; android?: AndroidFileSharerOptions; } ``` ### `AndroidFileSharerOptions` [Section titled “AndroidFileSharerOptions”](#androidfileshareroptions) ```typescript export interface AndroidFileSharerOptions { chooserTitle?: string; saveDirectory?: 'downloads' | 'pictures' | 'movies' | 'music' | 'documents'; relativePath?: string; } ``` ### `SaveFileResult` [Section titled “SaveFileResult”](#savefileresult) ```typescript export interface SaveFileResult { uri?: string; } ``` ## Error Codes [Section titled “Error Codes”](#error-codes) * `ERR_PARAM_NO_FILENAME` - `filename` is missing or blank. * `ERR_PARAM_NO_DATA` - neither `base64Data` nor `path` was provided. * `ERR_PARAM_DATA_INVALID` - base64 input could not be decoded. * `ERR_LOCAL_FILE_NOT_FOUND` - the provided local path or content URI could not be opened. * `ERR_FILE_CACHING_FAILED` - the native temporary file could not be written. * `ERR_FILE_SAVE_FAILED` - Android could not save the file to public storage. * `ERR_ACTIVITY_NOT_FOUND` - Android could not open a share target. * `USER_CANCELLED` - the iOS share sheet was dismissed without completing. ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page tracks the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # Getting Started > Install @capgo/capacitor-file and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-file bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { CapacitorFile } from '@capgo/capacitor-file'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `requestFileSystem` [Section titled “requestFileSystem”](#requestfilesystem) Request a file system. ```typescript import { CapacitorFile } from '@capgo/capacitor-file'; await CapacitorFile.requestFileSystem({} as RequestFileSystemOptions); ``` ### `resolveLocalFileSystemURL` [Section titled “resolveLocalFileSystemURL”](#resolvelocalfilesystemurl) Resolve a file URL to an entry. ```typescript import { CapacitorFile } from '@capgo/capacitor-file'; await CapacitorFile.resolveLocalFileSystemURL({} as ResolveURLOptions); ``` ### `getFile` [Section titled “getFile”](#getfile) Get a file entry. ```typescript import { CapacitorFile } from '@capgo/capacitor-file'; await CapacitorFile.getFile({} as GetFileOptions); ``` ### `getDirectory` [Section titled “getDirectory”](#getdirectory) Get a directory entry. ```typescript import { CapacitorFile } from '@capgo/capacitor-file'; await CapacitorFile.getDirectory({} as GetDirectoryOptions); ``` ### `readFile` [Section titled “readFile”](#readfile) Read a file as text or base64. ```typescript import { CapacitorFile } from '@capgo/capacitor-file'; await CapacitorFile.readFile({} as ReadFileOptions); ``` ### `readAsDataURL` [Section titled “readAsDataURL”](#readasdataurl) Read a file as a data URL (base64 with MIME type prefix). ```typescript import { CapacitorFile } from '@capgo/capacitor-file'; await CapacitorFile.readAsDataURL({} as ReadFileOptions); ``` ### `writeFile` [Section titled “writeFile”](#writefile) Write data to a file. ```typescript import { CapacitorFile } from '@capgo/capacitor-file'; await CapacitorFile.writeFile({} as WriteFileOptions); ``` ### `appendFile` [Section titled “appendFile”](#appendfile) Append data to a file. ```typescript import { CapacitorFile } from '@capgo/capacitor-file'; await CapacitorFile.appendFile({} as WriteFileOptions); ``` ### `deleteFile` [Section titled “deleteFile”](#deletefile) Delete a file. ```typescript import { CapacitorFile } from '@capgo/capacitor-file'; await CapacitorFile.deleteFile({} as DeleteFileOptions); ``` ### `mkdir` [Section titled “mkdir”](#mkdir) Create a directory. ```typescript import { CapacitorFile } from '@capgo/capacitor-file'; await CapacitorFile.mkdir({} as MkdirOptions); ``` ### `rmdir` [Section titled “rmdir”](#rmdir) Delete a directory. ```typescript import { CapacitorFile } from '@capgo/capacitor-file'; await CapacitorFile.rmdir({} as DeleteDirectoryOptions); ``` ### `readdir` [Section titled “readdir”](#readdir) Read directory contents. ```typescript import { CapacitorFile } from '@capgo/capacitor-file'; await CapacitorFile.readdir({} as ReaddirOptions); ``` ### `stat` [Section titled “stat”](#stat) Get metadata about a file or directory. ```typescript import { CapacitorFile } from '@capgo/capacitor-file'; await CapacitorFile.stat({} as StatOptions); ``` ### `getMetadata` [Section titled “getMetadata”](#getmetadata) Get metadata about a file or directory. Alias for stat(). ```typescript import { CapacitorFile } from '@capgo/capacitor-file'; await CapacitorFile.getMetadata({} as StatOptions); ``` ### `rename` [Section titled “rename”](#rename) Rename or move a file or directory. ```typescript import { CapacitorFile } from '@capgo/capacitor-file'; await CapacitorFile.rename({} as RenameOptions); ``` ### `move` [Section titled “move”](#move) Move a file or directory. Alias for rename(). ```typescript import { CapacitorFile } from '@capgo/capacitor-file'; await CapacitorFile.move({} as RenameOptions); ``` ### `copy` [Section titled “copy”](#copy) Copy a file or directory. ```typescript import { CapacitorFile } from '@capgo/capacitor-file'; await CapacitorFile.copy({} as CopyOptions); ``` ### `exists` [Section titled “exists”](#exists) Check if a file or directory exists. ```typescript import { CapacitorFile } from '@capgo/capacitor-file'; await CapacitorFile.exists({} as ExistsOptions); ``` ### `getUri` [Section titled “getUri”](#geturi) Get the URI for a file. ```typescript import { CapacitorFile } from '@capgo/capacitor-file'; await CapacitorFile.getUri({} as GetUriOptions); ``` ### `truncate` [Section titled “truncate”](#truncate) Truncate a file to a specified size. ```typescript import { CapacitorFile } from '@capgo/capacitor-file'; await CapacitorFile.truncate({} as TruncateOptions); ``` ### `getDirectories` [Section titled “getDirectories”](#getdirectories) Get all known file system directories. ```typescript import { CapacitorFile } from '@capgo/capacitor-file'; await CapacitorFile.getDirectories(); ``` ### `getFreeDiskSpace` [Section titled “getFreeDiskSpace”](#getfreediskspace) Get the free disk space in bytes. ```typescript import { CapacitorFile } from '@capgo/capacitor-file'; await CapacitorFile.getFreeDiskSpace(); ``` ### `checkPermissions` [Section titled “checkPermissions”](#checkpermissions) Check the current permission status for file operations. On Android, this checks for external storage permissions. On iOS and web, this always returns ‘granted’ as no special permissions are needed. ```typescript import { CapacitorFile } from '@capgo/capacitor-file'; await CapacitorFile.checkPermissions(); ``` ### `requestPermissions` [Section titled “requestPermissions”](#requestpermissions) Request permissions for file operations. On Android, this requests external storage permissions needed for accessing files outside the app’s private directories. On iOS and web, this always returns ‘granted’ as no special permissions are needed. ```typescript import { CapacitorFile } from '@capgo/capacitor-file'; await CapacitorFile.requestPermissions(); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `RequestFileSystemOptions` [Section titled “RequestFileSystemOptions”](#requestfilesystemoptions) Options for requesting a file system. ```typescript export interface RequestFileSystemOptions { /** The type of file system to request */ type: FileSystemType; /** Requested size in bytes (may not be enforced on all platforms) */ size?: number; } ``` ### `FileSystem` [Section titled “FileSystem”](#filesystem) Represents a file system. ```typescript export interface FileSystem { /** The name of the file system */ name: string; /** The root directory of the file system */ root: DirectoryEntry; } ``` ### `ResolveURLOptions` [Section titled “ResolveURLOptions”](#resolveurloptions) Options for resolving a URL to an entry. ```typescript export interface ResolveURLOptions { /** The URL to resolve (file:// or cdvfile://) */ url: string; } ``` ### `Entry` [Section titled “Entry”](#entry) Represents a file or directory entry. ```typescript export interface Entry { /** True if this is a file */ isFile: boolean; /** True if this is a directory */ isDirectory: boolean; /** The name of the file or directory */ name: string; /** The full path relative to the filesystem root */ fullPath: string; /** The native file:// URI */ nativeURL: string; } ``` ### `GetFileOptions` [Section titled “GetFileOptions”](#getfileoptions) Options for getting a file. ```typescript export interface GetFileOptions { /** Path to the file */ path: string; /** Base directory */ directory?: Directory; /** Options for creating the file */ options?: GetOptions; } ``` ### `FileEntry` [Section titled “FileEntry”](#fileentry) Represents a file entry. ```typescript export interface FileEntry extends Entry { isFile: true; isDirectory: false; } ``` ### `GetDirectoryOptions` [Section titled “GetDirectoryOptions”](#getdirectoryoptions) Options for getting a directory. ```typescript export interface GetDirectoryOptions { /** Path to the directory */ path: string; /** Base directory */ directory?: Directory; /** Options for creating the directory */ options?: GetOptions; } ``` ### `DirectoryEntry` [Section titled “DirectoryEntry”](#directoryentry) Represents a directory entry. ```typescript export interface DirectoryEntry extends Entry { isFile: false; isDirectory: true; } ``` ### `ReadFileOptions` [Section titled “ReadFileOptions”](#readfileoptions) Options for reading a file. ```typescript export interface ReadFileOptions { /** Path to the file */ path: string; /** Base directory */ directory?: Directory; /** Encoding for text files (omit for binary/base64) */ encoding?: Encoding; /** Byte offset to start reading from (default: 0) */ offset?: number; /** Number of bytes to read (default: read to end of file) */ length?: number; } ``` ### `ReadFileResult` [Section titled “ReadFileResult”](#readfileresult) Result of reading a file. ```typescript export interface ReadFileResult { /** File contents as string (text) or base64 (binary) */ data: string; } ``` ### `WriteFileOptions` [Section titled “WriteFileOptions”](#writefileoptions) Options for writing a file. ```typescript export interface WriteFileOptions { /** Path to the file */ path: string; /** Base directory */ directory?: Directory; /** Data to write (string for text, base64 for binary) */ data: string; /** Encoding for text files */ encoding?: Encoding; /** If true, append to existing file instead of overwriting */ append?: boolean; /** Create intermediate directories if they don't exist */ recursive?: boolean; /** Byte position to start writing at (for random access writes). If not specified, writes from beginning or appends based on 'append' flag */ position?: number; } ``` ### `WriteFileResult` [Section titled “WriteFileResult”](#writefileresult) Result of writing a file. ```typescript export interface WriteFileResult { /** The URI of the written file */ uri: string; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-firebase-analytics > Capacitor plugin for Firebase Analytics. ## Overview [Section titled “Overview”](#overview) Capacitor plugin for Firebase Analytics. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `getAppInstanceId` - Retrieves the app instance id. * `getSessionId` - Retrieves the current session id (`ga_session_id`). * `setConsent` - Sets the user’s consent mode. * `setUserId` - Sets the user ID property. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | | `getAppInstanceId` | Retrieves the app instance id. | | `getSessionId` | Retrieves the current session id (`ga_session_id`). | | `setConsent` | Sets the user’s consent mode. | | `setUserId` | Sets the user ID property. | | `setUserProperty` | Sets a custom user property to a given value. | | `setCurrentScreen` | Sets the current screen name. | | `logEvent` | Logs an app event. | | `setSessionTimeoutDuration` | Sets the duration of inactivity that terminates the current session. | | `setEnabled` | Enables/disables automatic data collection. The value does not apply until the next run of the app. | | `isEnabled` | Returns whether or not automatic data collection is enabled. | | `resetAnalyticsData` | Clears all analytics data for this app from the device. Resets the app instance id. | | `initiateOnDeviceConversionMeasurementWithEmailAddress` | Initiates on-device conversion measurement with an email address. | | `initiateOnDeviceConversionMeasurementWithPhoneNumber` | Initiates on-device conversion measurement with a phone number. | | `initiateOnDeviceConversionMeasurementWithHashedEmailAddress` | Initiates on-device conversion measurement with a hashed email address. | | `initiateOnDeviceConversionMeasurementWithHashedPhoneNumber` | Initiates on-device conversion measurement with a hashed phone number. | | `getPluginVersion` | Get the version of this plugin. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-firebase](https://github.com/Cap-go/capacitor-firebase/). # Getting Started > Install @capgo/capacitor-firebase-analytics and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-firebase-analytics bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { FirebaseAnalytics } from '@capgo/capacitor-firebase-analytics'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `getAppInstanceId` [Section titled “getAppInstanceId”](#getappinstanceid) Retrieves the app instance id. Only available for Android and iOS. ```typescript import { FirebaseAnalytics } from '@capgo/capacitor-firebase-analytics'; await FirebaseAnalytics.getAppInstanceId(); ``` ### `getSessionId` [Section titled “getSessionId”](#getsessionid) Retrieves the current session id (`ga_session_id`). Only available for Android and iOS. ```typescript import { FirebaseAnalytics } from '@capgo/capacitor-firebase-analytics'; await FirebaseAnalytics.getSessionId(); ``` ### `setConsent` [Section titled “setConsent”](#setconsent) Sets the user’s consent mode. ```typescript import { FirebaseAnalytics } from '@capgo/capacitor-firebase-analytics'; await FirebaseAnalytics.setConsent({} as SetConsentOptions); ``` ### `setUserId` [Section titled “setUserId”](#setuserid) Sets the user ID property. ```typescript import { FirebaseAnalytics } from '@capgo/capacitor-firebase-analytics'; await FirebaseAnalytics.setUserId({} as SetUserIdOptions); ``` ### `setUserProperty` [Section titled “setUserProperty”](#setuserproperty) Sets a custom user property to a given value. ```typescript import { FirebaseAnalytics } from '@capgo/capacitor-firebase-analytics'; await FirebaseAnalytics.setUserProperty({} as SetUserPropertyOptions); ``` ### `setCurrentScreen` [Section titled “setCurrentScreen”](#setcurrentscreen) Sets the current screen name. ```typescript import { FirebaseAnalytics } from '@capgo/capacitor-firebase-analytics'; await FirebaseAnalytics.setCurrentScreen({} as SetCurrentScreenOptions); ``` ### `logEvent` [Section titled “logEvent”](#logevent) Logs an app event. ```typescript import { FirebaseAnalytics } from '@capgo/capacitor-firebase-analytics'; await FirebaseAnalytics.logEvent({} as LogEventOptions); ``` ### `setSessionTimeoutDuration` [Section titled “setSessionTimeoutDuration”](#setsessiontimeoutduration) Sets the duration of inactivity that terminates the current session. Only available for Android and iOS. ```typescript import { FirebaseAnalytics } from '@capgo/capacitor-firebase-analytics'; await FirebaseAnalytics.setSessionTimeoutDuration({} as SetSessionTimeoutDurationOptions); ``` ### `setEnabled` [Section titled “setEnabled”](#setenabled) Enables/disables automatic data collection. The value does not apply until the next run of the app. ```typescript import { FirebaseAnalytics } from '@capgo/capacitor-firebase-analytics'; await FirebaseAnalytics.setEnabled({} as SetEnabledOptions); ``` ### `isEnabled` [Section titled “isEnabled”](#isenabled) Returns whether or not automatic data collection is enabled. Only available for Web. ```typescript import { FirebaseAnalytics } from '@capgo/capacitor-firebase-analytics'; await FirebaseAnalytics.isEnabled(); ``` ### `resetAnalyticsData` [Section titled “resetAnalyticsData”](#resetanalyticsdata) Clears all analytics data for this app from the device. Resets the app instance id. Only available for Android and iOS. ```typescript import { FirebaseAnalytics } from '@capgo/capacitor-firebase-analytics'; await FirebaseAnalytics.resetAnalyticsData(); ``` ### `initiateOnDeviceConversionMeasurementWithEmailAddress` [Section titled “initiateOnDeviceConversionMeasurementWithEmailAddress”](#initiateondeviceconversionmeasurementwithemailaddress) Initiates on-device conversion measurement with an email address. Only available for iOS. ```typescript import { FirebaseAnalytics } from '@capgo/capacitor-firebase-analytics'; await FirebaseAnalytics.initiateOnDeviceConversionMeasurementWithEmailAddress({} as InitiateOnDeviceConversionMeasurementWithEmailAddressOptions); ``` ### `initiateOnDeviceConversionMeasurementWithPhoneNumber` [Section titled “initiateOnDeviceConversionMeasurementWithPhoneNumber”](#initiateondeviceconversionmeasurementwithphonenumber) Initiates on-device conversion measurement with a phone number. Only available for iOS. ```typescript import { FirebaseAnalytics } from '@capgo/capacitor-firebase-analytics'; await FirebaseAnalytics.initiateOnDeviceConversionMeasurementWithPhoneNumber({} as InitiateOnDeviceConversionMeasurementWithPhoneNumberOptions); ``` ### `initiateOnDeviceConversionMeasurementWithHashedEmailAddress` [Section titled “initiateOnDeviceConversionMeasurementWithHashedEmailAddress”](#initiateondeviceconversionmeasurementwithhashedemailaddress) Initiates on-device conversion measurement with a hashed email address. Only available for iOS. ```typescript import { FirebaseAnalytics } from '@capgo/capacitor-firebase-analytics'; await FirebaseAnalytics.initiateOnDeviceConversionMeasurementWithHashedEmailAddress({} as InitiateOnDeviceConversionMeasurementWithHashedEmailAddressOptions); ``` ### `initiateOnDeviceConversionMeasurementWithHashedPhoneNumber` [Section titled “initiateOnDeviceConversionMeasurementWithHashedPhoneNumber”](#initiateondeviceconversionmeasurementwithhashedphonenumber) Initiates on-device conversion measurement with a hashed phone number. Only available for iOS. ```typescript import { FirebaseAnalytics } from '@capgo/capacitor-firebase-analytics'; await FirebaseAnalytics.initiateOnDeviceConversionMeasurementWithHashedPhoneNumber({} as InitiateOnDeviceConversionMeasurementWithHashedPhoneNumberOptions); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `GetAppInstanceIdResult` [Section titled “GetAppInstanceIdResult”](#getappinstanceidresult) ```typescript export interface GetAppInstanceIdResult { /** * The app instance id. * * Not defined if `FirebaseAnalytics.ConsentType.ANALYTICS_STORAGE` has been set to `FirebaseAnalytics.ConsentStatus.DENIED`. * * @since 1.4.0 */ appInstanceId?: string; } ``` ### `GetSessionIdResult` [Section titled “GetSessionIdResult”](#getsessionidresult) ```typescript export interface GetSessionIdResult { /** * The current session id. * * Matches Firebase Analytics `ga_session_id`. * * Not defined if `FirebaseAnalytics.ConsentType.ANALYTICS_STORAGE` has been set to `FirebaseAnalytics.ConsentStatus.DENIED`. * * @since 8.0.1 */ sessionId?: number; } ``` ### `SetConsentOptions` [Section titled “SetConsentOptions”](#setconsentoptions) ```typescript export interface SetConsentOptions { /** * The consent type. * * @since 6.0.0 */ type: ConsentType; /** * The consent status. * * @since 6.0.0 */ status: ConsentStatus; } ``` ### `SetUserIdOptions` [Section titled “SetUserIdOptions”](#setuseridoptions) ```typescript export interface SetUserIdOptions { /** * @since 0.1.0 */ userId: string | null; } ``` ### `SetUserPropertyOptions` [Section titled “SetUserPropertyOptions”](#setuserpropertyoptions) ```typescript export interface SetUserPropertyOptions { /** * @since 0.1.0 */ key: string; /** * @since 0.1.0 */ value: string | null; } ``` ### `SetCurrentScreenOptions` [Section titled “SetCurrentScreenOptions”](#setcurrentscreenoptions) ```typescript export interface SetCurrentScreenOptions { /** * @since 0.1.0 */ screenName: string | null; /** * Only available for Android and iOS. * * @default null * @since 0.1.0 */ screenClassOverride?: string | null; } ``` ### `LogEventOptions` [Section titled “LogEventOptions”](#logeventoptions) ```typescript export interface LogEventOptions { /** * The event name. * * @since 0.1.0 */ name: string; /** * The optional event params. * * @since 0.1.0 */ params?: { [key: string]: any }; } ``` ### `SetSessionTimeoutDurationOptions` [Section titled “SetSessionTimeoutDurationOptions”](#setsessiontimeoutdurationoptions) ```typescript export interface SetSessionTimeoutDurationOptions { /** * Duration in seconds. * * @default 1800 * @since 0.1.0 */ duration: number; } ``` ### `SetEnabledOptions` [Section titled “SetEnabledOptions”](#setenabledoptions) ```typescript export interface SetEnabledOptions { /** * @since 0.1.0 */ enabled: boolean; } ``` ### `IsEnabledResult` [Section titled “IsEnabledResult”](#isenabledresult) ```typescript export interface IsEnabledResult { /** * @since 0.1.0 */ enabled: boolean; } ``` ### `InitiateOnDeviceConversionMeasurementWithEmailAddressOptions` [Section titled “InitiateOnDeviceConversionMeasurementWithEmailAddressOptions”](#initiateondeviceconversionmeasurementwithemailaddressoptions) ```typescript export interface InitiateOnDeviceConversionMeasurementWithEmailAddressOptions { /** * The email address to initiate on-device conversion measurement with. * * @since 7.2.0 */ emailAddress: string; } ``` ### `InitiateOnDeviceConversionMeasurementWithPhoneNumberOptions` [Section titled “InitiateOnDeviceConversionMeasurementWithPhoneNumberOptions”](#initiateondeviceconversionmeasurementwithphonenumberoptions) ```typescript export interface InitiateOnDeviceConversionMeasurementWithPhoneNumberOptions { /** * The phone number to initiate on-device conversion measurement with. * * @since 7.2.0 */ phoneNumber: string; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-firebase-app > Capacitor plugin for Firebase App. ## Overview [Section titled “Overview”](#overview) Capacitor plugin for Firebase App. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `getName` - Get the name for this app. * `getOptions` - Get the configuration options for this app. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------ | ------------------------------------------- | | `getName` | Get the name for this app. | | `getOptions` | Get the configuration options for this app. | | `getPluginVersion` | Get the version of this plugin. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-firebase](https://github.com/Cap-go/capacitor-firebase/). # @capgo/capacitor-firebase-app-check > Capacitor plugin for Firebase App Check. ## Overview [Section titled “Overview”](#overview) Capacitor plugin for Firebase App Check. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `getToken` - Get the current App Check token. * `initialize` - Activate App Check for the given app. Can be called only once per app. * `setTokenAutoRefreshEnabled` - Set whether the App Check token should be refreshed automatically or not. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ---------------------------- | ------------------------------------------------------------------------- | | `getToken` | Get the current App Check token. | | `initialize` | Activate App Check for the given app. Can be called only once per app. | | `setTokenAutoRefreshEnabled` | Set whether the App Check token should be refreshed automatically or not. | | `addListener` | Called when the App Check token changed. | | `removeAllListeners` | Remove all listeners for this plugin. | | `getPluginVersion` | Get the version of this plugin. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-firebase](https://github.com/Cap-go/capacitor-firebase/). # Getting Started > Install @capgo/capacitor-firebase-app-check and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-firebase-app-check bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { FirebaseAppCheck } from '@capgo/capacitor-firebase-app-check'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `getToken` [Section titled “getToken”](#gettoken) Get the current App Check token. ```typescript import { FirebaseAppCheck } from '@capgo/capacitor-firebase-app-check'; await FirebaseAppCheck.getToken(); ``` ### `initialize` [Section titled “initialize”](#initialize) Activate App Check for the given app. Can be called only once per app. ```typescript import { FirebaseAppCheck } from '@capgo/capacitor-firebase-app-check'; await FirebaseAppCheck.initialize(); ``` ### `setTokenAutoRefreshEnabled` [Section titled “setTokenAutoRefreshEnabled”](#settokenautorefreshenabled) Set whether the App Check token should be refreshed automatically or not. ```typescript import { FirebaseAppCheck } from '@capgo/capacitor-firebase-app-check'; await FirebaseAppCheck.setTokenAutoRefreshEnabled({} as SetTokenAutoRefreshEnabledOptions); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `GetTokenOptions` [Section titled “GetTokenOptions”](#gettokenoptions) ```typescript export interface GetTokenOptions { /** * If `true`, will always try to fetch a fresh token. * If `false`, will use a cached token if found in storage. * * @since 1.3.0 * @default false */ forceRefresh?: boolean; } ``` ### `GetTokenResult` [Section titled “GetTokenResult”](#gettokenresult) ```typescript export interface GetTokenResult { /** * The App Check token in JWT format. * * @since 1.3.0 */ token: string; /** * The timestamp after which the token will expire in milliseconds since epoch. * * Only available for Android and iOS. * * @since 1.3.0 */ expireTimeMillis?: number; } ``` ### `InitializeOptions` [Section titled “InitializeOptions”](#initializeoptions) ```typescript export interface InitializeOptions { /** * If `true`, the debug provider is used. * * ⚠️ **Attention**: The debug provider allows access to your Firebase resources from unverified devices. * Don't use the debug provider in production builds of your app, and don't share your debug builds with untrusted parties. * * ⚠️ **Deprecated**: Use `debugToken` instead. This option will be removed in the next major version. * * Read more: https://firebase.google.com/docs/app-check/web/debug-provider * * @since 1.3.0 * @deprecated Use `debugToken` instead. This option will be removed in the next major version. * @default false */ debug?: boolean; /** * If `true`, the debug provider is used. * * On **Web**, you can also set a predefined debug token string instead of `true`. On Android and iOS, you have to use environment variables for this. * * ⚠️ **Attention**: The debug provider allows access to your Firebase resources from unverified devices. * Don't use the debug provider in production builds of your app, and don't share your debug builds with untrusted parties. * * @since 7.1.0 * @default false * @see https://firebase.google.com/docs/app-check/android/debug-provider#ci * @see https://firebase.google.com/docs/app-check/ios/debug-provider#ci * @see https://firebase.google.com/docs/app-check/web/debug-provider */ debugToken?: boolean | string; /** * If `true`, the SDK automatically refreshes App Check tokens as needed. * * @since 1.3.0 * @default false */ isTokenAutoRefreshEnabled?: boolean; /** * The provider to use for App Check. Must be an instance of * `ReCaptchaV3Provider`, `ReCaptchaEnterpriseProvider`, or `CustomProvider`. * * Only available for Web. * * @since 7.1.0 * @default ReCaptchaV3Provider * @see https://firebase.google.com/docs/app-check/web/custom-provider */ provider?: any; /** * The reCAPTCHA v3 site key (public key). This option is ignored when `provider` is set. * * Only available for Web. * * @deprecated Use `provider` instead. * @since 1.3.0 */ siteKey?: string; } ``` ### `SetTokenAutoRefreshEnabledOptions` [Section titled “SetTokenAutoRefreshEnabledOptions”](#settokenautorefreshenabledoptions) ```typescript export interface SetTokenAutoRefreshEnabledOptions { /** * If `true`, the SDK automatically refreshes App Check tokens as needed. * This overrides any value set during initializeAppCheck(). * * @since 1.3.0 */ enabled: boolean; } ``` ### `TokenChangedListener` [Section titled “TokenChangedListener”](#tokenchangedlistener) Callback to receive the token change event. ```typescript export type TokenChangedListener = (event: TokenChangedEvent) => void; ``` ### `GetPluginVersionResult` [Section titled “GetPluginVersionResult”](#getpluginversionresult) ```typescript export interface GetPluginVersionResult { /** * The semantic version of this plugin. * * @since 8.0.1 */ version: string; } ``` ### `TokenChangedEvent` [Section titled “TokenChangedEvent”](#tokenchangedevent) ```typescript export interface TokenChangedEvent { /** * The App Check token in JWT format. * * @since 1.3.0 */ token: string; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # Getting Started > Install @capgo/capacitor-firebase-app and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-firebase-app bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { FirebaseApp } from '@capgo/capacitor-firebase-app'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `getName` [Section titled “getName”](#getname) Get the name for this app. ```typescript import { FirebaseApp } from '@capgo/capacitor-firebase-app'; await FirebaseApp.getName(); ``` ### `getOptions` [Section titled “getOptions”](#getoptions) Get the configuration options for this app. ```typescript import { FirebaseApp } from '@capgo/capacitor-firebase-app'; await FirebaseApp.getOptions(); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `GetNameResult` [Section titled “GetNameResult”](#getnameresult) ```typescript export interface GetNameResult { /** * The unique name of this app. * * @since 0.1.0 */ name: string; } ``` ### `GetOptionsResult` [Section titled “GetOptionsResult”](#getoptionsresult) ```typescript export interface GetOptionsResult { /** * API key used for authenticating requests from your app. * * @since 0.1.0 */ apiKey: string; /** * Google App ID used to uniquely identify an instance of an app. * * @since 0.1.0 */ applicationId: string; /** * The database root URL. * * @since 0.1.0 */ databaseUrl: string; /** * The Project Number. * * @since 0.1.0 */ gcmSenderId: string; /** * The Google Cloud project ID. * * @since 0.1.0 */ projectId: string; /** * The Google Cloud Storage bucket name. * * @since 0.1.0 */ storageBucket: string; } ``` ### `GetPluginVersionResult` [Section titled “GetPluginVersionResult”](#getpluginversionresult) ```typescript export interface GetPluginVersionResult { /** * The semantic version of this plugin. * * @since 8.0.1 */ version: string; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-firebase-authentication > Capacitor plugin for Firebase Authentication. ## Overview [Section titled “Overview”](#overview) Capacitor plugin for Firebase Authentication. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `applyActionCode` - Applies a verification code sent to the user by email. * `confirmPasswordReset` - Completes the password reset process. * `confirmVerificationCode` - Finishes the phone number verification process. * `createUserWithEmailAndPassword` - Creates a new user account with email and password. If the new account was created, the user is signed in automatically. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------ | | `applyActionCode` | Applies a verification code sent to the user by email. | | `confirmPasswordReset` | Completes the password reset process. | | `confirmVerificationCode` | Finishes the phone number verification process. | | `createUserWithEmailAndPassword` | Creates a new user account with email and password. If the new account was created, the user is signed in automatically. | | `deleteUser` | Deletes and signs out the user. | | `fetchSignInMethodsForEmail` | Fetches the sign-in methods for an email address. | | `getCurrentUser` | Fetches the currently signed-in user. | | `getPendingAuthResult` | Returns the `SignInResult` if your app launched a web sign-in flow and the OS cleans up the app while in the background. | | `getIdToken` | Fetches the Firebase Auth ID Token for the currently signed-in user. | | `getIdTokenResult` | Returns a deserialized JSON Web Token (JWT) used to identify the user to a Firebase service. | | `getRedirectResult` | Returns the `SignInResult` from the redirect-based sign-in flow. | | `getTenantId` | Get the tenant id. | | `isSignInWithEmailLink` | Checks if an incoming link is a sign-in with email link suitable for `signInWithEmailLink`. | | `linkWithApple` | Links the user account with Apple authentication provider. | | `linkWithEmailAndPassword` | Links the user account with Email authentication provider. | | `linkWithEmailLink` | Links the user account with Email authentication provider. | | `linkWithFacebook` | Links the user account with Facebook authentication provider. | | `linkWithGameCenter` | Links the user account with Game Center authentication provider. | | `linkWithGithub` | Links the user account with GitHub authentication provider. | | `linkWithGoogle` | Links the user account with Google authentication provider. | | `linkWithMicrosoft` | Links the user account with Microsoft authentication provider. | | `linkWithOpenIdConnect` | Links the user account with an OpenID Connect provider. | | `linkWithPhoneNumber` | Links the user account with Phone Number authentication provider. | | `linkWithPlayGames` | Links the user account with Play Games authentication provider. | | `linkWithTwitter` | Links the user account with Twitter authentication provider. | | `linkWithYahoo` | Links the user account with Yahoo authentication provider. | | `reload` | Reloads user account data, if signed in. | | `revokeAccessToken` | Revokes the given access token. Currently only supports Apple OAuth access tokens. | | `sendEmailVerification` | Sends a verification email to the currently signed in user. | | `sendPasswordResetEmail` | Sends a password reset email. | | `sendSignInLinkToEmail` | Sends a sign-in email link to the user with the specified email. | | `setLanguageCode` | Sets the user-facing language code for auth operations. | | `setPersistence` | Sets the type of persistence for the currently saved auth session. | | `setTenantId` | Sets the tenant id. | | `signInAnonymously` | Signs in as an anonymous user. | | `signInWithApple` | Starts the Apple sign-in flow. | | `signInWithCustomToken` | Starts the Custom Token sign-in flow. | | `signInWithEmailAndPassword` | Starts the sign-in flow using an email and password. | | `signInWithEmailLink` | Signs in using an email and sign-in email link. | | `signInWithFacebook` | Starts the Facebook sign-in flow. | | `signInWithGameCenter` | Starts the Game Center sign-in flow. | | `signInWithGithub` | Starts the GitHub sign-in flow. | | `signInWithGoogle` | Starts the Google sign-in flow. | | `signInWithMicrosoft` | Starts the Microsoft sign-in flow. | | `signInWithOpenIdConnect` | Starts the OpenID Connect sign-in flow. | | `signInWithPhoneNumber` | Starts the sign-in flow using a phone number. | | `signInWithPlayGames` | Starts the Play Games sign-in flow. | | `signInWithTwitter` | Starts the Twitter sign-in flow. | | `signInWithYahoo` | Starts the Yahoo sign-in flow. | | `signOut` | Starts the sign-out flow. | | `unlink` | Unlinks a provider from a user account. | | `updateEmail` | Updates the email address of the currently signed in user. | | `updatePassword` | Updates the password of the currently signed in user. | | `updateProfile` | Updates a user’s profile data. | | `useAppLanguage` | Sets the user-facing language code to be the default app language. | | `useEmulator` | Instrument your app to talk to the Authentication emulator. | | `verifyBeforeUpdateEmail` | Verifies the new email address before updating the email address of the currently signed in user. | | `checkAppTrackingTransparencyPermission` | Checks the current status of app tracking transparency. | | `requestAppTrackingTransparencyPermission` | Opens the system dialog to authorize app tracking transparency. | | `addListener` | Listen for the user’s sign-in state changes. | | `addListener` | Listen to ID token changes for the currently signed-in user. | | `addListener` | Listen for a completed phone verification. | | `addListener` | Listen for a failed phone verification. | | `addListener` | Listen for a phone verification code. | | `removeAllListeners` | Remove all listeners for this plugin. | | `getPluginVersion` | Get the version of this plugin. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-firebase](https://github.com/Cap-go/capacitor-firebase/). # Getting Started > Install @capgo/capacitor-firebase-authentication and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-firebase-authentication bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `applyActionCode` [Section titled “applyActionCode”](#applyactioncode) Applies a verification code sent to the user by email. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.applyActionCode({} as ApplyActionCodeOptions); ``` ### `confirmPasswordReset` [Section titled “confirmPasswordReset”](#confirmpasswordreset) Completes the password reset process. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.confirmPasswordReset({} as ConfirmPasswordResetOptions); ``` ### `confirmVerificationCode` [Section titled “confirmVerificationCode”](#confirmverificationcode) Finishes the phone number verification process. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.confirmVerificationCode({} as ConfirmVerificationCodeOptions); ``` ### `createUserWithEmailAndPassword` [Section titled “createUserWithEmailAndPassword”](#createuserwithemailandpassword) Creates a new user account with email and password. If the new account was created, the user is signed in automatically. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.createUserWithEmailAndPassword({} as CreateUserWithEmailAndPasswordOptions); ``` ### `deleteUser` [Section titled “deleteUser”](#deleteuser) Deletes and signs out the user. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.deleteUser(); ``` ### `fetchSignInMethodsForEmail` [Section titled “fetchSignInMethodsForEmail”](#fetchsigninmethodsforemail) Fetches the sign-in methods for an email address. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.fetchSignInMethodsForEmail({} as FetchSignInMethodsForEmailOptions); ``` ### `getCurrentUser` [Section titled “getCurrentUser”](#getcurrentuser) Fetches the currently signed-in user. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.getCurrentUser(); ``` ### `getPendingAuthResult` [Section titled “getPendingAuthResult”](#getpendingauthresult) Returns the `SignInResult` if your app launched a web sign-in flow and the OS cleans up the app while in the background. Only available for Android. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.getPendingAuthResult(); ``` ### `getIdToken` [Section titled “getIdToken”](#getidtoken) Fetches the Firebase Auth ID Token for the currently signed-in user. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.getIdToken(); ``` ### `getIdTokenResult` [Section titled “getIdTokenResult”](#getidtokenresult) Returns a deserialized JSON Web Token (JWT) used to identify the user to a Firebase service. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.getIdTokenResult(); ``` ### `getRedirectResult` [Section titled “getRedirectResult”](#getredirectresult) Returns the `SignInResult` from the redirect-based sign-in flow. If sign-in was unsuccessful, fails with an error. If no redirect operation was called, returns a `SignInResult` with a null user. Only available for Web. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.getRedirectResult(); ``` ### `getTenantId` [Section titled “getTenantId”](#gettenantid) Get the tenant id. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.getTenantId(); ``` ### `isSignInWithEmailLink` [Section titled “isSignInWithEmailLink”](#issigninwithemaillink) Checks if an incoming link is a sign-in with email link suitable for `signInWithEmailLink`. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.isSignInWithEmailLink({} as IsSignInWithEmailLinkOptions); ``` ### `linkWithApple` [Section titled “linkWithApple”](#linkwithapple) Links the user account with Apple authentication provider. The user must be logged in on the native layer. The `skipNativeAuth` configuration option has no effect here. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.linkWithApple(); ``` ### `linkWithEmailAndPassword` [Section titled “linkWithEmailAndPassword”](#linkwithemailandpassword) Links the user account with Email authentication provider. The user must be logged in on the native layer. The `skipNativeAuth` configuration option has no effect here. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.linkWithEmailAndPassword({} as LinkWithEmailAndPasswordOptions); ``` ### `linkWithEmailLink` [Section titled “linkWithEmailLink”](#linkwithemaillink) Links the user account with Email authentication provider. The user must be logged in on the native layer. The `skipNativeAuth` configuration option has no effect here. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.linkWithEmailLink({} as LinkWithEmailLinkOptions); ``` ### `linkWithFacebook` [Section titled “linkWithFacebook”](#linkwithfacebook) Links the user account with Facebook authentication provider. The user must be logged in on the native layer. The `skipNativeAuth` configuration option has no effect here. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.linkWithFacebook(); ``` ### `linkWithGameCenter` [Section titled “linkWithGameCenter”](#linkwithgamecenter) Links the user account with Game Center authentication provider. The user must be logged in on the native layer. The `skipNativeAuth` configuration option has no effect here. Only available for iOS. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.linkWithGameCenter(); ``` ### `linkWithGithub` [Section titled “linkWithGithub”](#linkwithgithub) Links the user account with GitHub authentication provider. The user must be logged in on the native layer. The `skipNativeAuth` configuration option has no effect here. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.linkWithGithub(); ``` ### `linkWithGoogle` [Section titled “linkWithGoogle”](#linkwithgoogle) Links the user account with Google authentication provider. The user must be logged in on the native layer. The `skipNativeAuth` configuration option has no effect here. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.linkWithGoogle(); ``` ### `linkWithMicrosoft` [Section titled “linkWithMicrosoft”](#linkwithmicrosoft) Links the user account with Microsoft authentication provider. The user must be logged in on the native layer. The `skipNativeAuth` configuration option has no effect here. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.linkWithMicrosoft(); ``` ### `linkWithOpenIdConnect` [Section titled “linkWithOpenIdConnect”](#linkwithopenidconnect) Links the user account with an OpenID Connect provider. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.linkWithOpenIdConnect({} as LinkWithOpenIdConnectOptions); ``` ### `linkWithPhoneNumber` [Section titled “linkWithPhoneNumber”](#linkwithphonenumber) Links the user account with Phone Number authentication provider. The user must be logged in on the native layer. The `skipNativeAuth` configuration option has no effect here. Use the `phoneVerificationCompleted` listener to be notified when the verification is completed. Use the `phoneVerificationFailed` listener to be notified when the verification is failed. Use the `phoneCodeSent` listener to get the verification id. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.linkWithPhoneNumber({} as LinkWithPhoneNumberOptions); ``` ### `linkWithPlayGames` [Section titled “linkWithPlayGames”](#linkwithplaygames) Links the user account with Play Games authentication provider. The user must be logged in on the native layer. The `skipNativeAuth` configuration option has no effect here. Only available for Android. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.linkWithPlayGames(); ``` ### `linkWithTwitter` [Section titled “linkWithTwitter”](#linkwithtwitter) Links the user account with Twitter authentication provider. The user must be logged in on the native layer. The `skipNativeAuth` configuration option has no effect here. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.linkWithTwitter(); ``` ### `linkWithYahoo` [Section titled “linkWithYahoo”](#linkwithyahoo) Links the user account with Yahoo authentication provider. The user must be logged in on the native layer. The `skipNativeAuth` configuration option has no effect here. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.linkWithYahoo(); ``` ### `reload` [Section titled “reload”](#reload) Reloads user account data, if signed in. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.reload(); ``` ### `revokeAccessToken` [Section titled “revokeAccessToken”](#revokeaccesstoken) Revokes the given access token. Currently only supports Apple OAuth access tokens. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.revokeAccessToken({} as RevokeAccessTokenOptions); ``` ### `sendEmailVerification` [Section titled “sendEmailVerification”](#sendemailverification) Sends a verification email to the currently signed in user. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.sendEmailVerification(); ``` ### `sendPasswordResetEmail` [Section titled “sendPasswordResetEmail”](#sendpasswordresetemail) Sends a password reset email. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.sendPasswordResetEmail({} as SendPasswordResetEmailOptions); ``` ### `sendSignInLinkToEmail` [Section titled “sendSignInLinkToEmail”](#sendsigninlinktoemail) Sends a sign-in email link to the user with the specified email. To complete sign in with the email link, call `signInWithEmailLink` with the email address and the email link supplied in the email sent to the user. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.sendSignInLinkToEmail({} as SendSignInLinkToEmailOptions); ``` ### `setLanguageCode` [Section titled “setLanguageCode”](#setlanguagecode) Sets the user-facing language code for auth operations. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.setLanguageCode({} as SetLanguageCodeOptions); ``` ### `setPersistence` [Section titled “setPersistence”](#setpersistence) Sets the type of persistence for the currently saved auth session. Only available for Web. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.setPersistence({} as SetPersistenceOptions); ``` ### `setTenantId` [Section titled “setTenantId”](#settenantid) Sets the tenant id. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.setTenantId({} as SetTenantIdOptions); ``` ### `signInAnonymously` [Section titled “signInAnonymously”](#signinanonymously) Signs in as an anonymous user. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.signInAnonymously(); ``` ### `signInWithApple` [Section titled “signInWithApple”](#signinwithapple) Starts the Apple sign-in flow. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.signInWithApple(); ``` ### `signInWithCustomToken` [Section titled “signInWithCustomToken”](#signinwithcustomtoken) Starts the Custom Token sign-in flow. This method cannot be used in combination with `skipNativeAuth` on Android and iOS. In this case you have to use the `signInWithCustomToken` interface of the Firebase JS SDK directly. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.signInWithCustomToken({} as SignInWithCustomTokenOptions); ``` ### `signInWithEmailAndPassword` [Section titled “signInWithEmailAndPassword”](#signinwithemailandpassword) Starts the sign-in flow using an email and password. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.signInWithEmailAndPassword({} as SignInWithEmailAndPasswordOptions); ``` ### `signInWithEmailLink` [Section titled “signInWithEmailLink”](#signinwithemaillink) Signs in using an email and sign-in email link. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.signInWithEmailLink({} as SignInWithEmailLinkOptions); ``` ### `signInWithFacebook` [Section titled “signInWithFacebook”](#signinwithfacebook) Starts the Facebook sign-in flow. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.signInWithFacebook(); ``` ### `signInWithGameCenter` [Section titled “signInWithGameCenter”](#signinwithgamecenter) Starts the Game Center sign-in flow. Only available for iOS. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.signInWithGameCenter(); ``` ### `signInWithGithub` [Section titled “signInWithGithub”](#signinwithgithub) Starts the GitHub sign-in flow. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.signInWithGithub(); ``` ### `signInWithGoogle` [Section titled “signInWithGoogle”](#signinwithgoogle) Starts the Google sign-in flow. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.signInWithGoogle(); ``` ### `signInWithMicrosoft` [Section titled “signInWithMicrosoft”](#signinwithmicrosoft) Starts the Microsoft sign-in flow. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.signInWithMicrosoft(); ``` ### `signInWithOpenIdConnect` [Section titled “signInWithOpenIdConnect”](#signinwithopenidconnect) Starts the OpenID Connect sign-in flow. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.signInWithOpenIdConnect({} as SignInWithOpenIdConnectOptions); ``` ### `signInWithPhoneNumber` [Section titled “signInWithPhoneNumber”](#signinwithphonenumber) Starts the sign-in flow using a phone number. Use the `phoneVerificationCompleted` listener to be notified when the verification is completed. Use the `phoneVerificationFailed` listener to be notified when the verification is failed. Use the `phoneCodeSent` listener to get the verification id. Only available for Android and iOS. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.signInWithPhoneNumber({} as SignInWithPhoneNumberOptions); ``` ### `signInWithPlayGames` [Section titled “signInWithPlayGames”](#signinwithplaygames) Starts the Play Games sign-in flow. Only available for Android. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.signInWithPlayGames(); ``` ### `signInWithTwitter` [Section titled “signInWithTwitter”](#signinwithtwitter) Starts the Twitter sign-in flow. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.signInWithTwitter(); ``` ### `signInWithYahoo` [Section titled “signInWithYahoo”](#signinwithyahoo) Starts the Yahoo sign-in flow. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.signInWithYahoo(); ``` ### `signOut` [Section titled “signOut”](#signout) Starts the sign-out flow. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.signOut(); ``` ### `unlink` [Section titled “unlink”](#unlink) Unlinks a provider from a user account. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.unlink({} as UnlinkOptions); ``` ### `updateEmail` [Section titled “updateEmail”](#updateemail) Updates the email address of the currently signed in user. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.updateEmail({} as UpdateEmailOptions); ``` ### `updatePassword` [Section titled “updatePassword”](#updatepassword) Updates the password of the currently signed in user. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.updatePassword({} as UpdatePasswordOptions); ``` ### `updateProfile` [Section titled “updateProfile”](#updateprofile) Updates a user’s profile data. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.updateProfile({} as UpdateProfileOptions); ``` ### `useAppLanguage` [Section titled “useAppLanguage”](#useapplanguage) Sets the user-facing language code to be the default app language. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.useAppLanguage(); ``` ### `useEmulator` [Section titled “useEmulator”](#useemulator) Instrument your app to talk to the Authentication emulator. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.useEmulator({} as UseEmulatorOptions); ``` ### `verifyBeforeUpdateEmail` [Section titled “verifyBeforeUpdateEmail”](#verifybeforeupdateemail) Verifies the new email address before updating the email address of the currently signed in user. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.verifyBeforeUpdateEmail({} as VerifyBeforeUpdateEmailOptions); ``` ### `checkAppTrackingTransparencyPermission` [Section titled “checkAppTrackingTransparencyPermission”](#checkapptrackingtransparencypermission) Checks the current status of app tracking transparency. Only available on iOS. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.checkAppTrackingTransparencyPermission(); ``` ### `requestAppTrackingTransparencyPermission` [Section titled “requestAppTrackingTransparencyPermission”](#requestapptrackingtransparencypermission) Opens the system dialog to authorize app tracking transparency. **Attention:** The user may have disabled the tracking request in the device settings, see [Apple’s documentation](https://support.apple.com/guide/iphone/iph4f4cbd242/ios). Only available on iOS. ```typescript import { FirebaseAuthentication } from '@capgo/capacitor-firebase-authentication'; await FirebaseAuthentication.requestAppTrackingTransparencyPermission(); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `ApplyActionCodeOptions` [Section titled “ApplyActionCodeOptions”](#applyactioncodeoptions) ```typescript export interface ApplyActionCodeOptions { /** * A verification code sent to the user. * * @since 0.2.2 */ oobCode: string; } ``` ### `ConfirmPasswordResetOptions` [Section titled “ConfirmPasswordResetOptions”](#confirmpasswordresetoptions) ```typescript export interface ConfirmPasswordResetOptions { /** * A verification code sent to the user. * * @since 0.2.2 */ oobCode: string; /** * The new password. * * @since 0.2.2 */ newPassword: string; } ``` ### `ConfirmVerificationCodeOptions` [Section titled “ConfirmVerificationCodeOptions”](#confirmverificationcodeoptions) ```typescript export interface ConfirmVerificationCodeOptions { /** * The verification ID received from the `phoneCodeSent` listener. * * The `verificationCode` option must also be provided. * * @since 5.0.0 */ verificationId: string; /** * The verification code either received from the `phoneCodeSent` listener or entered by the user. * * The `verificationId` option must also be provided. * * @since 5.0.0 */ verificationCode: string; } ``` ### `SignInResult` [Section titled “SignInResult”](#signinresult) ```typescript export interface SignInResult { /** * The currently signed-in user, or null if there isn't any. * * @since 0.1.0 */ user: User | null; /** * Credentials returned by an auth provider. * * @since 0.1.0 */ credential: AuthCredential | null; /** * Additional user information from a federated identity provider. * * @since 0.5.1 */ additionalUserInfo: AdditionalUserInfo | null; } ``` ### `CreateUserWithEmailAndPasswordOptions` [Section titled “CreateUserWithEmailAndPasswordOptions”](#createuserwithemailandpasswordoptions) ```typescript export interface CreateUserWithEmailAndPasswordOptions { /** * @since 0.2.2 */ email: string; /** * @since 0.2.2 */ password: string; } ``` ### `FetchSignInMethodsForEmailOptions` [Section titled “FetchSignInMethodsForEmailOptions”](#fetchsigninmethodsforemailoptions) ```typescript export interface FetchSignInMethodsForEmailOptions { /** * The user's email address. * * @since 6.0.0 */ email: string; } ``` ### `FetchSignInMethodsForEmailResult` [Section titled “FetchSignInMethodsForEmailResult”](#fetchsigninmethodsforemailresult) ```typescript export interface FetchSignInMethodsForEmailResult { /** * The sign-in methods for the specified email address. * * This list is empty when [Email Enumeration Protection](https://cloud.google.com/identity-platform/docs/admin/email-enumeration-protection) * is enabled, irrespective of the number of authentication methods available for the given email. * * @since 6.0.0 */ signInMethods: string[]; } ``` ### `GetCurrentUserResult` [Section titled “GetCurrentUserResult”](#getcurrentuserresult) ```typescript export interface GetCurrentUserResult { /** * The currently signed-in user, or null if there isn't any. * * @since 0.1.0 */ user: User | null; } ``` ### `GetIdTokenOptions` [Section titled “GetIdTokenOptions”](#getidtokenoptions) ```typescript export interface GetIdTokenOptions { /** * Force refresh regardless of token expiration. * * @since 0.1.0 */ forceRefresh: boolean; } ``` ### `GetIdTokenResult` [Section titled “GetIdTokenResult”](#getidtokenresult-1) ```typescript export interface GetIdTokenResult { /** * The Firebase Auth ID token JWT string. * * @since 0.1.0 */ token: string; } ``` ### `GetIdTokenResultOptions` [Section titled “GetIdTokenResultOptions”](#getidtokenresultoptions) ```typescript export interface GetIdTokenResultOptions { /** * Force refresh regardless of token expiration. * * @since 7.4.0 */ forceRefresh: boolean; } ``` ### `GetIdTokenResultResult` [Section titled “GetIdTokenResultResult”](#getidtokenresultresult) ```typescript export interface GetIdTokenResultResult { /** * The authentication time in milliseconds since the epoch. * * This is the time the user authenticated (signed in) and not the time the token was refreshed. * * @since 7.4.0 */ authTime: number; /** * The ID token expiration time in milliseconds since the epoch. * * @since 7.4.0 */ expirationTime: number; /** * The ID token issuance time in milliseconds since the epoch. * * @since 7.4.0 */ issuedAtTime: number; /** * The sign-in provider through which the ID token was obtained. * * @since 7.4.0 */ signInProvider: string | null; /** * The type of second factor associated with this session, provided the user was multi-factor * authenticated (eg. phone, etc). * * @since 7.4.0 */ signInSecondFactor: string | null; /** * The entire payload claims of the ID token including the standard reserved claims as well as * the custom claims. * * @since 7.4.0 */ claims: Record; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-firebase-crashlytics > Capacitor plugin for Firebase Crashlytics. ## Overview [Section titled “Overview”](#overview) Capacitor plugin for Firebase Crashlytics. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `crash` - Forces a crash to test the implementation. * `setCustomKey` - Sets a custom key and value that is associated with subsequent fatal and non-fatal reports. * `setUserId` - Sets a user ID (identifier) that is associated with subsequent fatal and non-fatal reports. * `log` - Adds a custom log message that is sent with your crash data to give yourself more context for the events leading up to a crash. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | | `crash` | Forces a crash to test the implementation. | | `setCustomKey` | Sets a custom key and value that is associated with subsequent fatal and non-fatal reports. | | `setUserId` | Sets a user ID (identifier) that is associated with subsequent fatal and non-fatal reports. | | `log` | Adds a custom log message that is sent with your crash data to give yourself more context for the events leading up to a crash. | | `setEnabled` | Enables/disables automatic data collection. The value does not apply until the next run of the app. | | `isEnabled` | Returns whether automatic data collection is enabled. | | `didCrashOnPreviousExecution` | Returns whether the app crashed during the previous execution. | | `sendUnsentReports` | Uploads any unsent reports to Crashlytics at next startup. | | `deleteUnsentReports` | Deletes any unsent reports on the device. | | `recordException` | Records a non-fatal report to send to Crashlytics. | | `getPluginVersion` | Get the version of this plugin. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-firebase](https://github.com/Cap-go/capacitor-firebase/). # Getting Started > Install @capgo/capacitor-firebase-crashlytics and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-firebase-crashlytics bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { FirebaseCrashlytics } from '@capgo/capacitor-firebase-crashlytics'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `crash` [Section titled “crash”](#crash) Forces a crash to test the implementation. Only available for Android and iOS. ```typescript import { FirebaseCrashlytics } from '@capgo/capacitor-firebase-crashlytics'; await FirebaseCrashlytics.crash({} as CrashOptions); ``` ### `setCustomKey` [Section titled “setCustomKey”](#setcustomkey) Sets a custom key and value that is associated with subsequent fatal and non-fatal reports. Only available for Android and iOS. ```typescript import { FirebaseCrashlytics } from '@capgo/capacitor-firebase-crashlytics'; await FirebaseCrashlytics.setCustomKey({} as SetCustomKeyOptions); ``` ### `setUserId` [Section titled “setUserId”](#setuserid) Sets a user ID (identifier) that is associated with subsequent fatal and non-fatal reports. Only available for Android and iOS. ```typescript import { FirebaseCrashlytics } from '@capgo/capacitor-firebase-crashlytics'; await FirebaseCrashlytics.setUserId({} as SetUserIdOptions); ``` ### `log` [Section titled “log”](#log) Adds a custom log message that is sent with your crash data to give yourself more context for the events leading up to a crash. Only available for Android and iOS. ```typescript import { FirebaseCrashlytics } from '@capgo/capacitor-firebase-crashlytics'; await FirebaseCrashlytics.log({} as LogOptions); ``` ### `setEnabled` [Section titled “setEnabled”](#setenabled) Enables/disables automatic data collection. The value does not apply until the next run of the app. Only available for Android and iOS. ```typescript import { FirebaseCrashlytics } from '@capgo/capacitor-firebase-crashlytics'; await FirebaseCrashlytics.setEnabled({} as SetEnabledOptions); ``` ### `isEnabled` [Section titled “isEnabled”](#isenabled) Returns whether or not automatic data collection is enabled. Only available for iOS. ```typescript import { FirebaseCrashlytics } from '@capgo/capacitor-firebase-crashlytics'; await FirebaseCrashlytics.isEnabled(); ``` ### `didCrashOnPreviousExecution` [Section titled “didCrashOnPreviousExecution”](#didcrashonpreviousexecution) Returns whether the app crashed during the previous execution. Only available for Android and iOS. ```typescript import { FirebaseCrashlytics } from '@capgo/capacitor-firebase-crashlytics'; await FirebaseCrashlytics.didCrashOnPreviousExecution(); ``` ### `sendUnsentReports` [Section titled “sendUnsentReports”](#sendunsentreports) Uploads any unsent reports to Crashlytics at next startup. When automatic data collection is enabled, Crashlytics automatically uploads reports at startup. Only available for Android and iOS. ```typescript import { FirebaseCrashlytics } from '@capgo/capacitor-firebase-crashlytics'; await FirebaseCrashlytics.sendUnsentReports(); ``` ### `deleteUnsentReports` [Section titled “deleteUnsentReports”](#deleteunsentreports) Deletes any unsent reports on the device. Only available for Android and iOS. ```typescript import { FirebaseCrashlytics } from '@capgo/capacitor-firebase-crashlytics'; await FirebaseCrashlytics.deleteUnsentReports(); ``` ### `recordException` [Section titled “recordException”](#recordexception) Records a non-fatal report to send to Crashlytics. Only available for Android and iOS. ```typescript import { FirebaseCrashlytics } from '@capgo/capacitor-firebase-crashlytics'; await FirebaseCrashlytics.recordException({} as RecordExceptionOptions); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `CrashOptions` [Section titled “CrashOptions”](#crashoptions) ```typescript export interface CrashOptions { /** * @since 0.1.0 */ message: string; } ``` ### `SetCustomKeyOptions` [Section titled “SetCustomKeyOptions”](#setcustomkeyoptions) ```typescript export type SetCustomKeyOptions = CustomKeyAndValue; ``` ### `SetUserIdOptions` [Section titled “SetUserIdOptions”](#setuseridoptions) ```typescript export interface SetUserIdOptions { /** * @since 0.1.0 */ userId: string; } ``` ### `LogOptions` [Section titled “LogOptions”](#logoptions) ```typescript export interface LogOptions { /** * @since 0.1.0 */ message: string; } ``` ### `SetEnabledOptions` [Section titled “SetEnabledOptions”](#setenabledoptions) ```typescript export interface SetEnabledOptions { /** * @since 0.1.0 */ enabled: boolean; } ``` ### `IsEnabledResult` [Section titled “IsEnabledResult”](#isenabledresult) ```typescript export interface IsEnabledResult { /** * @since 0.1.0 */ enabled: boolean; } ``` ### `DidCrashOnPreviousExecutionResult` [Section titled “DidCrashOnPreviousExecutionResult”](#didcrashonpreviousexecutionresult) ```typescript export interface DidCrashOnPreviousExecutionResult { /** * @since 0.1.0 */ crashed: boolean; } ``` ### `RecordExceptionOptions` [Section titled “RecordExceptionOptions”](#recordexceptionoptions) ```typescript export interface RecordExceptionOptions { /** * The message to record as a non-fatal exception. * * @since 0.1.0 */ message: string; /** * Error code within a specific error domain. * * **Attention:** This option is ignored on iOS if `stacktrace` is provided. * * Only available for iOS. * * @since 0.1.0 */ code?: number; /** * A string containing the error domain. * * **Attention:** This option is ignored on iOS if `stacktrace` is provided. * * Only available for iOS. * * @since 0.1.0 */ domain?: string; /** * An array of keys and the values to associate with the non fatal exception, * in addition to the app level custom keys. * * **Attention:** This option is ignored on iOS if `stacktrace` is provided. * * @since 7.1.0 */ keysAndValues?: CustomKeyAndValue[]; /** * A stacktrace generated by stacktrace.js. * * @since 1.1.0 */ stacktrace?: StackFrame[]; } ``` ### `GetPluginVersionResult` [Section titled “GetPluginVersionResult”](#getpluginversionresult) ```typescript export interface GetPluginVersionResult { /** * The semantic version of this plugin. * * @since 8.0.2 */ version: string; } ``` ### `CustomKeyAndValue` [Section titled “CustomKeyAndValue”](#customkeyandvalue) ```typescript export interface CustomKeyAndValue { /** * @since 7.1.0 */ key: string; /** * @since 7.1.0 */ value: string | number | boolean; /** * @since 7.1.0 */ type: 'string' | 'long' | 'double' | 'boolean' | 'int' | 'float'; } ``` ### `StackFrame` [Section titled “StackFrame”](#stackframe) Subset of the Stacktrace generated by stacktrace.js. ```typescript export interface StackFrame { lineNumber?: number; fileName?: string; functionName?: string; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-firebase-firestore > Capacitor plugin for Firebase Cloud Firestore. ## Overview [Section titled “Overview”](#overview) Capacitor plugin for Firebase Cloud Firestore. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `addDocument` - Adds a new document to a collection with the given data. * `setDocument` - Writes to the document referred to by the specified reference. If the document does not yet exist, it will be created. * `getDocument` - Reads the document referred to by the specified reference. * `updateDocument` - Updates fields in the document referred to by the specified reference. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------------------------ | ---------------------------------------------------------------------------------------------------------------------- | | `addDocument` | Adds a new document to a collection with the given data. | | `setDocument` | Writes to the document referred to by the specified reference. If the document does not yet exist, it will be created. | | `getDocument` | Reads the document referred to by the specified reference. | | `updateDocument` | Updates fields in the document referred to by the specified reference. | | `deleteDocument` | Deletes the document referred to by the specified reference. | | `writeBatch` | Execute multiple write operations as a single batch. | | `getCollection` | Reads the collection referenced by the specified reference. | | `getCollectionGroup` | Reads the collection group referenced by the specified reference. | | `getCountFromServer` | Fetches the number of documents in a collection. | | `clearPersistence` | Clears the persistent storage. This includes pending writes and cached documents. | | `enableNetwork` | Re-enables use of the network. | | `disableNetwork` | Disables use of the network. | | `useEmulator` | Instrument your app to talk to the Firestore emulator. | | `addDocumentSnapshotListener` | Adds a listener for document snapshot events. | | `addCollectionSnapshotListener` | Adds a listener for collection snapshot events. | | `addCollectionGroupSnapshotListener` | Adds a listener for collection group snapshot events. | | `removeSnapshotListener` | Remove a listener for document or collection snapshot events. | | `removeAllListeners` | Remove all listeners for this plugin. | | `getPluginVersion` | Get the version of this plugin. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-firebase](https://github.com/Cap-go/capacitor-firebase/). # Getting Started > Install @capgo/capacitor-firebase-firestore and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-firebase-firestore bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { FirebaseFirestore } from '@capgo/capacitor-firebase-firestore'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `addDocument` [Section titled “addDocument”](#adddocument) Adds a new document to a collection with the given data. ```typescript import { FirebaseFirestore } from '@capgo/capacitor-firebase-firestore'; await FirebaseFirestore.addDocument({} as AddDocumentOptions); ``` ### `setDocument` [Section titled “setDocument”](#setdocument) Writes to the document referred to by the specified reference. If the document does not yet exist, it will be created. ```typescript import { FirebaseFirestore } from '@capgo/capacitor-firebase-firestore'; await FirebaseFirestore.setDocument({} as SetDocumentOptions); ``` ### `getDocument` [Section titled “getDocument”](#getdocument) Reads the document referred to by the specified reference. ```typescript import { FirebaseFirestore } from '@capgo/capacitor-firebase-firestore'; await FirebaseFirestore.getDocument({} as GetDocumentOptions); ``` ### `updateDocument` [Section titled “updateDocument”](#updatedocument) Updates fields in the document referred to by the specified reference. ```typescript import { FirebaseFirestore } from '@capgo/capacitor-firebase-firestore'; await FirebaseFirestore.updateDocument({} as UpdateDocumentOptions); ``` ### `deleteDocument` [Section titled “deleteDocument”](#deletedocument) Deletes the document referred to by the specified reference. ```typescript import { FirebaseFirestore } from '@capgo/capacitor-firebase-firestore'; await FirebaseFirestore.deleteDocument({} as DeleteDocumentOptions); ``` ### `writeBatch` [Section titled “writeBatch”](#writebatch) Execute multiple write operations as a single batch. ```typescript import { FirebaseFirestore } from '@capgo/capacitor-firebase-firestore'; await FirebaseFirestore.writeBatch({} as WriteBatchOptions); ``` ### `getCollection` [Section titled “getCollection”](#getcollection) Reads the collection referenced by the specified reference. ```typescript import { FirebaseFirestore } from '@capgo/capacitor-firebase-firestore'; await FirebaseFirestore.getCollection({} as GetCollectionOptions); ``` ### `getCollectionGroup` [Section titled “getCollectionGroup”](#getcollectiongroup) Reads the collection group referenced by the specified reference. ```typescript import { FirebaseFirestore } from '@capgo/capacitor-firebase-firestore'; await FirebaseFirestore.getCollectionGroup({} as GetCollectionGroupOptions); ``` ### `getCountFromServer` [Section titled “getCountFromServer”](#getcountfromserver) Fetches the number of documents in a collection. ```typescript import { FirebaseFirestore } from '@capgo/capacitor-firebase-firestore'; await FirebaseFirestore.getCountFromServer({} as GetCountFromServerOptions); ``` ### `clearPersistence` [Section titled “clearPersistence”](#clearpersistence) Clears the persistent storage. This includes pending writes and cached documents. Must be called after the app is shutdown or when the app is first initialized. ```typescript import { FirebaseFirestore } from '@capgo/capacitor-firebase-firestore'; await FirebaseFirestore.clearPersistence(); ``` ### `enableNetwork` [Section titled “enableNetwork”](#enablenetwork) Re-enables use of the network. ```typescript import { FirebaseFirestore } from '@capgo/capacitor-firebase-firestore'; await FirebaseFirestore.enableNetwork(); ``` ### `disableNetwork` [Section titled “disableNetwork”](#disablenetwork) Disables use of the network. ```typescript import { FirebaseFirestore } from '@capgo/capacitor-firebase-firestore'; await FirebaseFirestore.disableNetwork(); ``` ### `useEmulator` [Section titled “useEmulator”](#useemulator) Instrument your app to talk to the Firestore emulator. ```typescript import { FirebaseFirestore } from '@capgo/capacitor-firebase-firestore'; await FirebaseFirestore.useEmulator({} as UseEmulatorOptions); ``` ### `addDocumentSnapshotListener` [Section titled “addDocumentSnapshotListener”](#adddocumentsnapshotlistener) Adds a listener for document snapshot events. ```typescript import { FirebaseFirestore } from '@capgo/capacitor-firebase-firestore'; await FirebaseFirestore.addDocumentSnapshotListener({} as AddDocumentSnapshotListenerOptions, {} as AddDocumentSnapshotListenerCallback); ``` ### `addCollectionSnapshotListener` [Section titled “addCollectionSnapshotListener”](#addcollectionsnapshotlistener) Adds a listener for collection snapshot events. ```typescript import { FirebaseFirestore } from '@capgo/capacitor-firebase-firestore'; await FirebaseFirestore.addCollectionSnapshotListener({} as AddCollectionSnapshotListenerOptions, {} as AddCollectionSnapshotListenerCallback); ``` ### `addCollectionGroupSnapshotListener` [Section titled “addCollectionGroupSnapshotListener”](#addcollectiongroupsnapshotlistener) Adds a listener for collection group snapshot events. ```typescript import { FirebaseFirestore } from '@capgo/capacitor-firebase-firestore'; await FirebaseFirestore.addCollectionGroupSnapshotListener({} as AddCollectionGroupSnapshotListenerOptions, {} as AddCollectionGroupSnapshotListenerCallback); ``` ### `removeSnapshotListener` [Section titled “removeSnapshotListener”](#removesnapshotlistener) Remove a listener for document or collection snapshot events. ```typescript import { FirebaseFirestore } from '@capgo/capacitor-firebase-firestore'; await FirebaseFirestore.removeSnapshotListener({} as RemoveSnapshotListenerOptions); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `AddDocumentOptions` [Section titled “AddDocumentOptions”](#adddocumentoptions) ```typescript export interface AddDocumentOptions { /** * The reference as a string, with path components separated by a forward slash (`/`). * * @since 5.2.0 * @example 'users' */ reference: string; /** * An object containing the data for the new document. * * @since 5.2.0 * @example { first: 'Alan', last: 'Turing', born: 1912 } */ data: DocumentData; } ``` ### `AddDocumentResult` [Section titled “AddDocumentResult”](#adddocumentresult) ```typescript export interface AddDocumentResult { /** * The reference of the newly added document. * * @since 5.2.0 */ reference: DocumentReference; } ``` ### `SetDocumentOptions` [Section titled “SetDocumentOptions”](#setdocumentoptions) ```typescript export interface SetDocumentOptions { /** * The reference as a string, with path components separated by a forward slash (`/`). * * @since 5.2.0 * @example 'users/Aorq09lkt1ynbR7xhTUx' */ reference: string; /** * An object containing the data for the new document. * * @since 5.2.0 * @example { first: 'Alan', last: 'Turing', born: 1912 } */ data: DocumentData; /** * Whether to merge the provided data with an existing document. * * @since 5.2.0 * @example true * @default false */ merge?: boolean; } ``` ### `DocumentData` [Section titled “DocumentData”](#documentdata) ```typescript export interface DocumentData { /** * A mapping between a field and its value. * * @since 5.2.0 */ [field: string]: any; } ``` ### `GetDocumentOptions` [Section titled “GetDocumentOptions”](#getdocumentoptions) ```typescript export interface GetDocumentOptions { /** * The reference as a string, with path components separated by a forward slash (`/`). * * @since 5.2.0 */ reference: string; } ``` ### `GetDocumentResult` [Section titled “GetDocumentResult”](#getdocumentresult) ```typescript export interface GetDocumentResult { /** * The current document contents. * * @since 5.2.0 */ snapshot: DocumentSnapshot; } ``` ### `UpdateDocumentOptions` [Section titled “UpdateDocumentOptions”](#updatedocumentoptions) ```typescript export interface UpdateDocumentOptions { /** * The reference as a string, with path components separated by a forward slash (`/`). * * @since 5.2.0 */ reference: string; /** * An object containing the data for the new document. * * @since 5.2.0 * @example { first: 'Alan', last: 'Turing', born: 1912 } */ data: DocumentData; } ``` ### `DeleteDocumentOptions` [Section titled “DeleteDocumentOptions”](#deletedocumentoptions) ```typescript export interface DeleteDocumentOptions { /** * The reference as a string, with path components separated by a forward slash (`/`). * * @since 5.2.0 */ reference: string; } ``` ### `WriteBatchOptions` [Section titled “WriteBatchOptions”](#writebatchoptions) ```typescript export interface WriteBatchOptions { /** * The operations to execute in the batch. * * @since 6.1.0 */ operations: WriteBatchOperation[]; } ``` ### `GetCollectionOptions` [Section titled “GetCollectionOptions”](#getcollectionoptions) ```typescript export interface GetCollectionOptions { /** * The reference as a string, with path components separated by a forward slash (`/`). * * @since 5.2.0 */ reference: string; /** * The filter to apply. * * @since 5.2.0 */ compositeFilter?: QueryCompositeFilterConstraint; /** * Narrow or order the set of documents to retrieve, but do not explicitly filter for document fields. * * @since 5.2.0 */ queryConstraints?: QueryNonFilterConstraint[]; } ``` ### `GetCollectionResult` [Section titled “GetCollectionResult”](#getcollectionresult) ```typescript export interface GetCollectionResult { /** * The documents in the collection. * * @since 5.2.0 */ snapshots: DocumentSnapshot[]; } ``` ### `GetCollectionGroupOptions` [Section titled “GetCollectionGroupOptions”](#getcollectiongroupoptions) ```typescript export interface GetCollectionGroupOptions { /** * The reference as a string, with path components separated by a forward slash (`/`). * * @since 5.2.0 */ reference: string; /** * The filter to apply. * * @since 5.2.0 */ compositeFilter?: QueryCompositeFilterConstraint; /** * Narrow or order the set of documents to retrieve, but do not explicitly filter for document fields. * * @since 5.2.0 */ queryConstraints?: QueryNonFilterConstraint[]; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-firebase-functions > Capacitor plugin for Firebase Cloud Functions. ## Overview [Section titled “Overview”](#overview) Capacitor plugin for Firebase Cloud Functions. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `callByName` - Call a callable function by name. * `callByUrl` - Call a callable function by URL. * `useEmulator` - Instrument your app to talk to the Cloud Functions emulator. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------ | ------------------------------------------------------------ | | `callByName` | Call a callable function by name. | | `callByUrl` | Call a callable function by URL. | | `useEmulator` | Instrument your app to talk to the Cloud Functions emulator. | | `getPluginVersion` | Get the version of this plugin. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-firebase](https://github.com/Cap-go/capacitor-firebase/). # Getting Started > Install @capgo/capacitor-firebase-functions and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-firebase-functions bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { FirebaseFunctions } from '@capgo/capacitor-firebase-functions'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `callByName` [Section titled “callByName”](#callbyname) Call a callable function by name. ```typescript import { FirebaseFunctions } from '@capgo/capacitor-firebase-functions'; await FirebaseFunctions.callByName({} as CallByNameOptions); ``` ### `callByUrl` [Section titled “callByUrl”](#callbyurl) Call a callable function by URL. ```typescript import { FirebaseFunctions } from '@capgo/capacitor-firebase-functions'; await FirebaseFunctions.callByUrl({} as CallByUrlOptions); ``` ### `useEmulator` [Section titled “useEmulator”](#useemulator) Instrument your app to talk to the Cloud Functions emulator. On Android, the cleartext traffic must be allowed. On the Capacitor configuration: ```plaintext { server: { cleartext: true } } ``` **The cleartext traffic is not intended for use in production.** ```typescript import { FirebaseFunctions } from '@capgo/capacitor-firebase-functions'; await FirebaseFunctions.useEmulator({} as UseEmulatorOptions); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `CallByNameOptions` [Section titled “CallByNameOptions”](#callbynameoptions) ```typescript export interface CallByNameOptions extends CallOptions { /** * The name of the callable function. * * @example 'myFunction' * @since 6.1.0 */ name: string; /** * The region of the callable function. * * @example 'us-central1' * @since 6.1.0 */ region?: string; } ``` ### `CallByNameResult` [Section titled “CallByNameResult”](#callbynameresult) ```typescript export type CallByNameResult = CallResult; ``` ### `CallByUrlOptions` [Section titled “CallByUrlOptions”](#callbyurloptions) ```typescript export interface CallByUrlOptions extends CallOptions { /** * The URL of the callable function. * * @example 'https://us-central1-my-project.cloudfunctions.net/myFunction' * @since 6.1.0 */ url: string; } ``` ### `CallByUrlResult` [Section titled “CallByUrlResult”](#callbyurlresult) ```typescript export type CallByUrlResult = CallResult; ``` ### `UseEmulatorOptions` [Section titled “UseEmulatorOptions”](#useemulatoroptions) ```typescript export interface UseEmulatorOptions { /** * The emulator host without any port or scheme. * * Note when using a Android Emulator device: 10.0.2.2 is the special IP address to connect to the 'localhost' of the host computer. * * @since 6.1.0 * @example "127.0.0.1" */ host: string; /** * The emulator port. * * @since 6.1.0 * @default 5001 * @example 5001 */ port?: number; /** * The region the callable functions are located in or a custom domain hosting the callable functions. * * @example 'us-central1' * @example 'https://mydomain.com' */ regionOrCustomDomain?: string; } ``` ### `GetPluginVersionResult` [Section titled “GetPluginVersionResult”](#getpluginversionresult) ```typescript export interface GetPluginVersionResult { /** * The semantic version of this plugin. * * @since 8.0.1 */ version: string; } ``` ### `CallResult` [Section titled “CallResult”](#callresult) ```typescript export interface CallResult { /** * The result of the callable function. * * @since 6.1.0 */ data: ResponseData; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-firebase-messaging > Capacitor plugin for Firebase Cloud Messaging (FCM). ## Overview [Section titled “Overview”](#overview) Capacitor plugin for Firebase Cloud Messaging (FCM). ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `checkPermissions` - Check permission to receive push notifications. * `requestPermissions` - Request permission to receive push notifications. * `isSupported` - Checks if all required APIs exist. * `getToken` - Register the app to receive push notifications. Returns a FCM token that can be used to send push messages to that Messaging instance. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | --------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | | `checkPermissions` | Check permission to receive push notifications. | | `requestPermissions` | Request permission to receive push notifications. | | `isSupported` | Checks if all required APIs exist. | | `getToken` | Register the app to receive push notifications. Returns a FCM token that can be used to send push messages to that Messaging instance. | | `deleteToken` | Delete the FCM token and unregister the app to stop receiving push notifications. Can be called, for example, when a user signs out. | | `getDeliveredNotifications` | Get a list of notifications that are visible on the notifications screen. | | `removeDeliveredNotifications` | Remove specific notifications from the notifications screen. | | `removeAllDeliveredNotifications` | Remove all notifications from the notifications screen. | | `subscribeToTopic` | Subscribes to topic in the background. | | `unsubscribeFromTopic` | Unsubscribes from topic in the background. | | `createChannel` | Create a notification channel. | | `deleteChannel` | Delete a notification channel. | | `listChannels` | List the available notification channels. | | `addListener` | Called when a new FCM token is received. | | `addListener` | Called when a new push notification is received. | | `addListener` | Called when a new push notification action is performed. | | `removeAllListeners` | Remove all listeners for this plugin. | | `getPluginVersion` | Get the version of this plugin. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-firebase](https://github.com/Cap-go/capacitor-firebase/). # Getting Started > Install @capgo/capacitor-firebase-messaging and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-firebase-messaging bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { FirebaseMessaging } from '@capgo/capacitor-firebase-messaging'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `checkPermissions` [Section titled “checkPermissions”](#checkpermissions) Check permission to receive push notifications. On **Android**, this method only needs to be called on Android 13+. ```typescript import { FirebaseMessaging } from '@capgo/capacitor-firebase-messaging'; await FirebaseMessaging.checkPermissions(); ``` ### `requestPermissions` [Section titled “requestPermissions”](#requestpermissions) Request permission to receive push notifications. On **Android**, this method only needs to be called on Android 13+. ```typescript import { FirebaseMessaging } from '@capgo/capacitor-firebase-messaging'; await FirebaseMessaging.requestPermissions(); ``` ### `isSupported` [Section titled “isSupported”](#issupported) Checks if all required APIs exist. Always returns `true` on Android and iOS. ```typescript import { FirebaseMessaging } from '@capgo/capacitor-firebase-messaging'; await FirebaseMessaging.isSupported(); ``` ### `getToken` [Section titled “getToken”](#gettoken) Register the app to receive push notifications. Returns a FCM token that can be used to send push messages to that Messaging instance. This method also re-enables FCM auto-init. ```typescript import { FirebaseMessaging } from '@capgo/capacitor-firebase-messaging'; await FirebaseMessaging.getToken(); ``` ### `deleteToken` [Section titled “deleteToken”](#deletetoken) Delete the FCM token and unregister the app to stop receiving push notifications. Can be called, for example, when a user signs out. ```typescript import { FirebaseMessaging } from '@capgo/capacitor-firebase-messaging'; await FirebaseMessaging.deleteToken(); ``` ### `getDeliveredNotifications` [Section titled “getDeliveredNotifications”](#getdeliverednotifications) Get a list of notifications that are visible on the notifications screen. Note: This will return all delivered notifications, including local notifications, and not just FCM notifications. On Android, the data field of the FCM notification will NOT be included. ```typescript import { FirebaseMessaging } from '@capgo/capacitor-firebase-messaging'; await FirebaseMessaging.getDeliveredNotifications(); ``` ### `removeDeliveredNotifications` [Section titled “removeDeliveredNotifications”](#removedeliverednotifications) Remove specific notifications from the notifications screen. ```typescript import { FirebaseMessaging } from '@capgo/capacitor-firebase-messaging'; await FirebaseMessaging.removeDeliveredNotifications({} as RemoveDeliveredNotificationsOptions); ``` ### `removeAllDeliveredNotifications` [Section titled “removeAllDeliveredNotifications”](#removealldeliverednotifications) Remove all notifications from the notifications screen. Note: This will remove all delivered notifications, including local notifications, and not just FCM notifications. ```typescript import { FirebaseMessaging } from '@capgo/capacitor-firebase-messaging'; await FirebaseMessaging.removeAllDeliveredNotifications(); ``` ### `subscribeToTopic` [Section titled “subscribeToTopic”](#subscribetotopic) Subscribes to topic in the background. Only available for Android and iOS. ```typescript import { FirebaseMessaging } from '@capgo/capacitor-firebase-messaging'; await FirebaseMessaging.subscribeToTopic({} as SubscribeToTopicOptions); ``` ### `unsubscribeFromTopic` [Section titled “unsubscribeFromTopic”](#unsubscribefromtopic) Unsubscribes from topic in the background. Only available for Android and iOS. ```typescript import { FirebaseMessaging } from '@capgo/capacitor-firebase-messaging'; await FirebaseMessaging.unsubscribeFromTopic({} as UnsubscribeFromTopicOptions); ``` ### `createChannel` [Section titled “createChannel”](#createchannel) Create a notification channel. Only available for Android (SDK 26+). ```typescript import { FirebaseMessaging } from '@capgo/capacitor-firebase-messaging'; await FirebaseMessaging.createChannel({} as CreateChannelOptions); ``` ### `deleteChannel` [Section titled “deleteChannel”](#deletechannel) Delete a notification channel. Only available for Android (SDK 26+). ```typescript import { FirebaseMessaging } from '@capgo/capacitor-firebase-messaging'; await FirebaseMessaging.deleteChannel({} as DeleteChannelOptions); ``` ### `listChannels` [Section titled “listChannels”](#listchannels) List the available notification channels. Only available for Android (SDK 26+). ```typescript import { FirebaseMessaging } from '@capgo/capacitor-firebase-messaging'; await FirebaseMessaging.listChannels(); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `PermissionStatus` [Section titled “PermissionStatus”](#permissionstatus) ```typescript export interface PermissionStatus { /** * @since 0.2.2 */ receive: PermissionState; } ``` ### `IsSupportedResult` [Section titled “IsSupportedResult”](#issupportedresult) ```typescript export interface IsSupportedResult { /** * @since 0.3.1 */ isSupported: boolean; } ``` ### `GetTokenOptions` [Section titled “GetTokenOptions”](#gettokenoptions) ```typescript export interface GetTokenOptions { /** * Your VAPID public key, which is required to retrieve the current registration token on the web. * * Only available for Web. */ vapidKey?: string; /** * The service worker registration for receiving push messaging. * If the registration is not provided explicitly, you need to have a `firebase-messaging-sw.js` at your root location. * * Only available for Web. */ serviceWorkerRegistration?: ServiceWorkerRegistration; } ``` ### `GetTokenResult` [Section titled “GetTokenResult”](#gettokenresult) ```typescript export interface GetTokenResult { /** * @since 0.2.2 */ token: string; } ``` ### `GetDeliveredNotificationsResult` [Section titled “GetDeliveredNotificationsResult”](#getdeliverednotificationsresult) ```typescript export interface GetDeliveredNotificationsResult { /** * @since 0.2.2 */ notifications: Notification[]; } ``` ### `RemoveDeliveredNotificationsOptions` [Section titled “RemoveDeliveredNotificationsOptions”](#removedeliverednotificationsoptions) ```typescript export interface RemoveDeliveredNotificationsOptions { /** * @since 0.4.0 */ notifications: Notification[]; } ``` ### `SubscribeToTopicOptions` [Section titled “SubscribeToTopicOptions”](#subscribetotopicoptions) ```typescript export interface SubscribeToTopicOptions { /** * The name of the topic to subscribe. * * @since 0.2.2 */ topic: string; } ``` ### `UnsubscribeFromTopicOptions` [Section titled “UnsubscribeFromTopicOptions”](#unsubscribefromtopicoptions) ```typescript export interface UnsubscribeFromTopicOptions { /** * The name of the topic to unsubscribe from. * * @since 0.2.2 */ topic: string; } ``` ### `CreateChannelOptions` [Section titled “CreateChannelOptions”](#createchanneloptions) ```typescript export type CreateChannelOptions = Channel; ``` ### `DeleteChannelOptions` [Section titled “DeleteChannelOptions”](#deletechanneloptions) ```typescript export interface DeleteChannelOptions { /** * The channel identifier. * * @since 1.4.0 */ id: string; } ``` ### `ListChannelsResult` [Section titled “ListChannelsResult”](#listchannelsresult) ```typescript export interface ListChannelsResult { channels: Channel[]; } ``` ### `TokenReceivedListener` [Section titled “TokenReceivedListener”](#tokenreceivedlistener) Callback to receive the token received event. ```typescript export type TokenReceivedListener = (event: TokenReceivedEvent) => void; ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-firebase-performance > Capacitor plugin for Firebase Performance Monitoring. ## Overview [Section titled “Overview”](#overview) Capacitor plugin for Firebase Performance Monitoring. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `startTrace` - Starts a trace. * `stopTrace` - Stops a trace. * `incrementMetric` - Atomically increments the metric with the given name for the selected trace by the `incrementBy` value. * `setEnabled` - Enables or disables performance monitoring. Will be applied with the next start of the app. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------ | ------------------------------------------------------------------------------------------------------- | | `startTrace` | Starts a trace. | | `stopTrace` | Stops a trace. | | `incrementMetric` | Atomically increments the metric with the given name for the selected trace by the `incrementBy` value. | | `setEnabled` | Enables or disables performance monitoring. Will be applied with the next start of the app. | | `isEnabled` | Determines whether performance monitoring is enabled or disabled. | | `putAttribute` | Sets a custom attribute of a trace to a given value. | | `getAttribute` | Returns the value of a custom attribute of a trace. | | `getAttributes` | Gets the all the custom attributes of a trace with their values. | | `removeAttribute` | Removes a custom attribute from a trace given its name. | | `putMetric` | Sets the value of a custom metric. | | `getMetric` | Get the value of a custom metric by name. | | `record` | Records a trace given its name and options. | | `getPluginVersion` | Get the version of this plugin. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-firebase](https://github.com/Cap-go/capacitor-firebase/). # Getting Started > Install @capgo/capacitor-firebase-performance and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-firebase-performance bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { FirebasePerformance } from '@capgo/capacitor-firebase-performance'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `startTrace` [Section titled “startTrace”](#starttrace) Starts a trace. ```typescript import { FirebasePerformance } from '@capgo/capacitor-firebase-performance'; await FirebasePerformance.startTrace({} as StartTraceOptions); ``` ### `stopTrace` [Section titled “stopTrace”](#stoptrace) Stops a trace. ```typescript import { FirebasePerformance } from '@capgo/capacitor-firebase-performance'; await FirebasePerformance.stopTrace({} as StopTraceOptions); ``` ### `incrementMetric` [Section titled “incrementMetric”](#incrementmetric) Atomically increments the metric with the given name for the selected trace by the `incrementBy` value. ```typescript import { FirebasePerformance } from '@capgo/capacitor-firebase-performance'; await FirebasePerformance.incrementMetric({} as IncrementMetricOptions); ``` ### `setEnabled` [Section titled “setEnabled”](#setenabled) Enables or disables performance monitoring. Will be applied with the next start of the app. ```typescript import { FirebasePerformance } from '@capgo/capacitor-firebase-performance'; await FirebasePerformance.setEnabled({} as SetEnabledOptions); ``` ### `isEnabled` [Section titled “isEnabled”](#isenabled) Determines whether performance monitoring is enabled or disabled. ```typescript import { FirebasePerformance } from '@capgo/capacitor-firebase-performance'; await FirebasePerformance.isEnabled(); ``` ### `putAttribute` [Section titled “putAttribute”](#putattribute) Sets a custom attribute of a trace to a given value. ```typescript import { FirebasePerformance } from '@capgo/capacitor-firebase-performance'; await FirebasePerformance.putAttribute({} as PutAttributeOptions); ``` ### `getAttribute` [Section titled “getAttribute”](#getattribute) Returns the value of a custom attribute of a trace. ```typescript import { FirebasePerformance } from '@capgo/capacitor-firebase-performance'; await FirebasePerformance.getAttribute({} as GetAttributeOptions); ``` ### `getAttributes` [Section titled “getAttributes”](#getattributes) Gets the all the custom attributes of a trace with their values. ```typescript import { FirebasePerformance } from '@capgo/capacitor-firebase-performance'; await FirebasePerformance.getAttributes({} as GetAttributesOptions); ``` ### `removeAttribute` [Section titled “removeAttribute”](#removeattribute) Removes a custom attribute from a trace given its name. ```typescript import { FirebasePerformance } from '@capgo/capacitor-firebase-performance'; await FirebasePerformance.removeAttribute({} as RemoveAttributeOptions); ``` ### `putMetric` [Section titled “putMetric”](#putmetric) Sets the value of a custom metric. ```typescript import { FirebasePerformance } from '@capgo/capacitor-firebase-performance'; await FirebasePerformance.putMetric({} as PutMetricOptions); ``` ### `getMetric` [Section titled “getMetric”](#getmetric) Get the value of a custom metric by name. ```typescript import { FirebasePerformance } from '@capgo/capacitor-firebase-performance'; await FirebasePerformance.getMetric({} as GetMetricOptions); ``` ### `record` [Section titled “record”](#record) Records a trace given its name and options. Only available on web. ```typescript import { FirebasePerformance } from '@capgo/capacitor-firebase-performance'; await FirebasePerformance.record({} as RecordOptions); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `StartTraceOptions` [Section titled “StartTraceOptions”](#starttraceoptions) ```typescript export interface StartTraceOptions { /** * Custom trace name. * * Names for custom code traces must meet the following requirements: * no leading or trailing whitespace, no leading underscore (_) character, * and max length is 100 characters. * * @since 0.1.0 */ traceName: string; } ``` ### `StopTraceOptions` [Section titled “StopTraceOptions”](#stoptraceoptions) ```typescript export interface StopTraceOptions { /** * Name of the trace that was set with `startTrace`. * * @since 0.1.0 */ traceName: string; } ``` ### `IncrementMetricOptions` [Section titled “IncrementMetricOptions”](#incrementmetricoptions) ```typescript export interface IncrementMetricOptions { /** * Name of the trace that was set with `startTrace`. * * @since 0.1.0 */ traceName: string; /** * Name of the metric to be incremented. * * @since 0.1.0 */ metricName: string; /** * Amount by which the metric has to be incremented. * * @default 1 * @since 0.1.0 */ incrementBy?: number; } ``` ### `SetEnabledOptions` [Section titled “SetEnabledOptions”](#setenabledoptions) ```typescript export interface SetEnabledOptions { /** * Should performance monitoring be enabled. * * @since 0.1.0 */ enabled: boolean; } ``` ### `IsEnabledResult` [Section titled “IsEnabledResult”](#isenabledresult) ```typescript export interface IsEnabledResult { /** * `true` if performance monitoring is enabled, otherwise `false`. * * @since 0.1.0 */ enabled: boolean; } ``` ### `PutAttributeOptions` [Section titled “PutAttributeOptions”](#putattributeoptions) ```typescript export interface PutAttributeOptions { /** * Name of the trace to set its attribute. * * @since 6.3.0 */ traceName: string; /** * Name of the attribute to set its value. * * @since 6.3.0 * @example "experiment" */ attribute: string; /** * The value to set to the attribute. * * @since 6.3.0 * @example "A" */ value: string; } ``` ### `GetAttributeOptions` [Section titled “GetAttributeOptions”](#getattributeoptions) ```typescript export interface GetAttributeOptions { /** * Name of the trace to set its attribute. * * @since 6.3.0 */ traceName: string; /** * Name of the attribute to retrieve its value. * * @since 6.3.0 */ attribute: string; } ``` ### `GetAttributeResult` [Section titled “GetAttributeResult”](#getattributeresult) ```typescript export interface GetAttributeResult { /** * The value of the custom attribute. * * @since 6.3.0 */ value: string | null; } ``` ### `GetAttributesOptions` [Section titled “GetAttributesOptions”](#getattributesoptions) ```typescript export interface GetAttributesOptions { /** * Name of the trace to get its attributes. * * @since 6.3.0 */ traceName: string; } ``` ### `GetAttributesResult` [Section titled “GetAttributesResult”](#getattributesresult) ```typescript export interface GetAttributesResult { /** * A map of all custom attributes of a trace with their values. * * @since 6.3.0 */ attributes: { [key: string]: string }; } ``` ### `RemoveAttributeOptions` [Section titled “RemoveAttributeOptions”](#removeattributeoptions) ```typescript export type RemoveAttributeOptions = GetAttributeOptions; ``` ### `PutMetricOptions` [Section titled “PutMetricOptions”](#putmetricoptions) ```typescript export interface PutMetricOptions { /** * Name of the trace to set its metric. * * @since 6.3.0 */ traceName: string; /** * The metric name. * * @since 6.3.0 */ metricName: string; /** * The value to set for the metric. * The given value is floored down to the nearest integer. * * @since 6.3.0 */ num: number; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-firebase-remote-config > Capacitor plugin for Firebase Remote Config. ## Overview [Section titled “Overview”](#overview) Capacitor plugin for Firebase Remote Config. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `activate` - Make the last fetched configuration available to the getters. * `fetchAndActivate` - Perform fetch and activate operations. * `fetchConfig` - Fetch and cache configuration from the Remote Config service. * `getBoolean` - Get the value for the given key as a boolean. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ---------------------------- | ------------------------------------------------------------- | | `activate` | Make the last fetched configuration available to the getters. | | `fetchAndActivate` | Perform fetch and activate operations. | | `fetchConfig` | Fetch and cache configuration from the Remote Config service. | | `getBoolean` | Get the value for the given key as a boolean. | | `getNumber` | Get the value for the given key as a number. | | `getString` | Get the value for the given key as a string. | | `getInfo` | Get information about the last fetch operation. | | `setMinimumFetchInterval` | Set the minimum fetch interval. | | `setSettings` | Set the remote config settings. | | `addConfigUpdateListener` | Add a listener for the config update event. | | `removeConfigUpdateListener` | Remove a listener for the config update event. | | `removeAllListeners` | Remove all listeners for this plugin. | | `getPluginVersion` | Get the version of this plugin. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-firebase](https://github.com/Cap-go/capacitor-firebase/). # Getting Started > Install @capgo/capacitor-firebase-remote-config and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-firebase-remote-config bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { FirebaseRemoteConfig } from '@capgo/capacitor-firebase-remote-config'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `activate` [Section titled “activate”](#activate) Make the last fetched configuration available to the getters. ```typescript import { FirebaseRemoteConfig } from '@capgo/capacitor-firebase-remote-config'; await FirebaseRemoteConfig.activate(); ``` ### `fetchAndActivate` [Section titled “fetchAndActivate”](#fetchandactivate) Perform fetch and activate operations. ```typescript import { FirebaseRemoteConfig } from '@capgo/capacitor-firebase-remote-config'; await FirebaseRemoteConfig.fetchAndActivate(); ``` ### `fetchConfig` [Section titled “fetchConfig”](#fetchconfig) Fetch and cache configuration from the Remote Config service. ```typescript import { FirebaseRemoteConfig } from '@capgo/capacitor-firebase-remote-config'; await FirebaseRemoteConfig.fetchConfig(); ``` ### `getBoolean` [Section titled “getBoolean”](#getboolean) Get the value for the given key as a boolean. ```typescript import { FirebaseRemoteConfig } from '@capgo/capacitor-firebase-remote-config'; await FirebaseRemoteConfig.getBoolean({} as GetBooleanOptions); ``` ### `getNumber` [Section titled “getNumber”](#getnumber) Get the value for the given key as a number. ```typescript import { FirebaseRemoteConfig } from '@capgo/capacitor-firebase-remote-config'; await FirebaseRemoteConfig.getNumber({} as GetNumberOptions); ``` ### `getString` [Section titled “getString”](#getstring) Get the value for the given key as a string. ```typescript import { FirebaseRemoteConfig } from '@capgo/capacitor-firebase-remote-config'; await FirebaseRemoteConfig.getString({} as GetStringOptions); ``` ### `getInfo` [Section titled “getInfo”](#getinfo) Get information about the last fetch operation. ```typescript import { FirebaseRemoteConfig } from '@capgo/capacitor-firebase-remote-config'; await FirebaseRemoteConfig.getInfo(); ``` ### `setMinimumFetchInterval` [Section titled “setMinimumFetchInterval”](#setminimumfetchinterval) Set the minimum fetch interval. Only available for Web. ```typescript import { FirebaseRemoteConfig } from '@capgo/capacitor-firebase-remote-config'; await FirebaseRemoteConfig.setMinimumFetchInterval({} as SetMinimumFetchIntervalOptions); ``` ### `setSettings` [Section titled “setSettings”](#setsettings) Set the remote config settings. On Android, the settings values are persisted in SharedPreferences. ```typescript import { FirebaseRemoteConfig } from '@capgo/capacitor-firebase-remote-config'; await FirebaseRemoteConfig.setSettings({} as SetSettingsOptions); ``` ### `addConfigUpdateListener` [Section titled “addConfigUpdateListener”](#addconfigupdatelistener) Add a listener for the config update event. Only available for Android and iOS. ```typescript import { FirebaseRemoteConfig } from '@capgo/capacitor-firebase-remote-config'; await FirebaseRemoteConfig.addConfigUpdateListener({} as AddConfigUpdateListenerOptionsCallback); ``` ### `removeConfigUpdateListener` [Section titled “removeConfigUpdateListener”](#removeconfigupdatelistener) Remove a listener for the config update event. Only available for Android and iOS. ```typescript import { FirebaseRemoteConfig } from '@capgo/capacitor-firebase-remote-config'; await FirebaseRemoteConfig.removeConfigUpdateListener({} as RemoveConfigUpdateListenerOptions); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `FetchConfigOptions` [Section titled “FetchConfigOptions”](#fetchconfigoptions) ```typescript export interface FetchConfigOptions { /** * Define the maximum age in seconds of an entry in the config cache before it is considered stale. * During development, it's recommended to set a relatively low minimum fetch interval. * * Only available for Android and iOS. * * @since 1.3.0 * @default 43200 * @see https://firebase.google.com/docs/reference/js/firebase.remoteconfig.RemoteConfigSettings#minimumfetchintervalmillis */ minimumFetchIntervalInSeconds?: number; } ``` ### `GetBooleanOptions` [Section titled “GetBooleanOptions”](#getbooleanoptions) ```typescript export type GetBooleanOptions = GetOptions; ``` ### `GetBooleanResult` [Section titled “GetBooleanResult”](#getbooleanresult) ```typescript export interface GetBooleanResult { /** * The value for the given key as a boolean. * * @since 1.3.0 */ value: boolean; /** * Indicates at which source this value came from. * * Only available for Android and iOS. * * @since 1.3.0 */ source?: GetValueSource; } ``` ### `GetNumberOptions` [Section titled “GetNumberOptions”](#getnumberoptions) ```typescript export type GetNumberOptions = GetOptions; ``` ### `GetNumberResult` [Section titled “GetNumberResult”](#getnumberresult) ```typescript export interface GetNumberResult { /** * The value for the given key as a number. * * @since 1.3.0 */ value: number; /** * Indicates at which source this value came from. * * Only available for Android and iOS. * * @since 1.3.0 */ source?: GetValueSource; } ``` ### `GetStringOptions` [Section titled “GetStringOptions”](#getstringoptions) ```typescript export type GetStringOptions = GetOptions; ``` ### `GetStringResult` [Section titled “GetStringResult”](#getstringresult) ```typescript export interface GetStringResult { /** * The value for the given key as a string. * * @since 1.3.0 */ value: string; /** * Indicates at which source this value came from. * * Only available for Android and iOS. * * @since 1.3.0 */ source?: GetValueSource; } ``` ### `GetInfoResult` [Section titled “GetInfoResult”](#getinforesult) ```typescript export interface GetInfoResult { /** * The Unix timestamp in milliseconds of the last successful fetch, or -1 if no fetch has occurred or initialization is incomplete. * @since 7.5.0 * @example 1762864760 */ lastFetchTime: number; /** * The status of the last fetch attempt. * @since 7.5.0 * @example 1 */ lastFetchStatus: LastFetchStatus; } ``` ### `SetMinimumFetchIntervalOptions` [Section titled “SetMinimumFetchIntervalOptions”](#setminimumfetchintervaloptions) ```typescript export interface SetMinimumFetchIntervalOptions { /** * Define the maximum age in seconds of an entry in the config cache before it is considered stale. * During development, it's recommended to set a relatively low minimum fetch interval. * * @since 1.3.0 * @default 43200 * @see https://firebase.google.com/docs/reference/js/remote-config.remoteconfigsettings#remoteconfigsettingsminimumfetchintervalmillis */ minimumFetchIntervalInSeconds: number; } ``` ### `SetSettingsOptions` [Section titled “SetSettingsOptions”](#setsettingsoptions) ```typescript export interface SetSettingsOptions { /** * Defines the maximum amount of milliseconds to wait for a response when fetching configuration from the Remote Config server. * * @since 6.2.0 * @default 60 * @see https://firebase.google.com/docs/reference/js/remote-config.remoteconfigsettings#remoteconfigsettingsfetchtimeoutmillis */ fetchTimeoutInSeconds?: number; /** * Define the maximum age in seconds of an entry in the config cache before it is considered stale. * During development, it's recommended to set a relatively low minimum fetch interval. * * @since 6.2.0 * @default 43200 * @see https://firebase.google.com/docs/reference/js/remote-config.remoteconfigsettings#remoteconfigsettingsminimumfetchintervalmillis */ minimumFetchIntervalInSeconds?: number; } ``` ### `AddConfigUpdateListenerOptionsCallback` [Section titled “AddConfigUpdateListenerOptionsCallback”](#addconfigupdatelisteneroptionscallback) ```typescript export type AddConfigUpdateListenerOptionsCallback = ( event: AddConfigUpdateListenerOptionsCallbackEvent | null, error: any, ) => void; ``` ### `CallbackId` [Section titled “CallbackId”](#callbackid) ```typescript export type CallbackId = string; ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-firebase-storage > Capacitor plugin for Firebase Cloud Storage. ## Overview [Section titled “Overview”](#overview) Capacitor plugin for Firebase Cloud Storage. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `deleteFile` - Delete a file. * `getDownloadUrl` - Get the download url for a file. * `getMetadata` - Get the metadata for a file. * `listFiles` - List files in a directory. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------ | ---------------------------------------------------------- | | `deleteFile` | Delete a file. | | `getDownloadUrl` | Get the download url for a file. | | `getMetadata` | Get the metadata for a file. | | `listFiles` | List files in a directory. | | `updateMetadata` | Update the metadata for a file. | | `uploadFile` | Upload a file. | | `useEmulator` | Instrument your app to talk to the Cloud Storage emulator. | | `getPluginVersion` | Get the version of this plugin. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-firebase](https://github.com/Cap-go/capacitor-firebase/). # Getting Started > Install @capgo/capacitor-firebase-storage and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-firebase-storage bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { FirebaseStorage } from '@capgo/capacitor-firebase-storage'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `deleteFile` [Section titled “deleteFile”](#deletefile) Delete a file. ```typescript import { FirebaseStorage } from '@capgo/capacitor-firebase-storage'; await FirebaseStorage.deleteFile({} as DeleteFileOptions); ``` ### `getDownloadUrl` [Section titled “getDownloadUrl”](#getdownloadurl) Get the download url for a file. ```typescript import { FirebaseStorage } from '@capgo/capacitor-firebase-storage'; await FirebaseStorage.getDownloadUrl({} as GetDownloadUrlOptions); ``` ### `getMetadata` [Section titled “getMetadata”](#getmetadata) Get the metadata for a file. ```typescript import { FirebaseStorage } from '@capgo/capacitor-firebase-storage'; await FirebaseStorage.getMetadata({} as GetMetadataOptions); ``` ### `listFiles` [Section titled “listFiles”](#listfiles) List files in a directory. ```typescript import { FirebaseStorage } from '@capgo/capacitor-firebase-storage'; await FirebaseStorage.listFiles({} as ListFilesOptions); ``` ### `updateMetadata` [Section titled “updateMetadata”](#updatemetadata) Update the metadata for a file. ```typescript import { FirebaseStorage } from '@capgo/capacitor-firebase-storage'; await FirebaseStorage.updateMetadata({} as UpdateMetadataOptions); ``` ### `uploadFile` [Section titled “uploadFile”](#uploadfile) Upload a file. ```typescript import { FirebaseStorage } from '@capgo/capacitor-firebase-storage'; await FirebaseStorage.uploadFile({} as UploadFileOptions, {} as UploadFileCallback); ``` ### `useEmulator` [Section titled “useEmulator”](#useemulator) Instrument your app to talk to the Cloud Storage emulator. On Android, the cleartext traffic must be allowed. On the Capacitor configuration: ```plaintext { server: { cleartext: true } } ``` **The cleartext traffic is not intended for use in production.** ```typescript import { FirebaseStorage } from '@capgo/capacitor-firebase-storage'; await FirebaseStorage.useEmulator({} as UseEmulatorOptions); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `DeleteFileOptions` [Section titled “DeleteFileOptions”](#deletefileoptions) ```typescript export interface DeleteFileOptions { /** * The full path to the file to delete, including the file name. * * @since 5.3.0 * @example 'mountains.png' * @example 'images/mountains.png' */ path: string; } ``` ### `GetDownloadUrlOptions` [Section titled “GetDownloadUrlOptions”](#getdownloadurloptions) ```typescript export interface GetDownloadUrlOptions { /** * The full path to the file to get the download url for, including the file name. * * @since 5.3.0 * @example 'mountains.png' * @example 'images/mountains.png' */ path: string; } ``` ### `GetDownloadUrlResult` [Section titled “GetDownloadUrlResult”](#getdownloadurlresult) ```typescript export interface GetDownloadUrlResult { /** * The download url for the file. * * @since 5.3.0 */ downloadUrl: string; } ``` ### `GetMetadataOptions` [Section titled “GetMetadataOptions”](#getmetadataoptions) ```typescript export interface GetMetadataOptions { /** * The full path to the file to get the metadata for, including the file name. * * @since 5.3.0 * @example 'mountains.png' * @example 'images/mountains.png' */ path: string; } ``` ### `GetMetadataResult` [Section titled “GetMetadataResult”](#getmetadataresult) ```typescript export interface GetMetadataResult { /** * The bucket this file is contained in. * * @since 5.3.0 */ bucket: string; /** * The timestamp at which the file was created in milliseconds since the epoch. * * @since 5.3.0 * @example 1697304435933 */ createdAt?: number; /** * The object's generation. * * @since 5.3.0 * @see https://cloud.google.com/storage/docs/metadata#generation-number */ generation: string; /** * The md5 hash of the file. * * @since 5.3.0 */ md5Hash?: string; /** * The object's metadata generation. * * @since 5.3.0 * @see https://cloud.google.com/storage/docs/metadata#generation-number */ metadataGeneration: string; /** * The short name of this file, which is the last component of the full path. * * @since 5.3.0 * @example 'mountains.png' */ name?: string; /** * The full path to the file, including the file name. * * @since 5.3.0 * @example 'images/mountains.png' */ path?: string; /** * The size of the file in bytes. * * @since 5.3.0 */ size: number; /** * The timestamp at which the file was last updated in milliseconds since the epoch. * * @since 5.3.0 * @example 1697304435933 */ updatedAt: number; /** * Served as the `Cache-Control` header on object download. * * @since 6.1.0 */ cacheControl?: string; /** * Served as the `Content-Disposition` header on object download. * * @since 6.1.0 */ contentDisposition?: string; /** * Served as the `Content-Encoding` header on object download. * * @since 6.1.0 */ contentEncoding?: string; /** * Served as the `Content-Language` header on object download. * * @since 6.1.0 */ contentLanguage?: string; /** * Served as the `Content-Type` header on object download. * * @since 6.1.0 */ contentType?: string; /** * Additional user-defined custom metadata. * * @since 6.1.0 */ customMetadata?: { [key: string]: string }; } ``` ### `ListFilesOptions` [Section titled “ListFilesOptions”](#listfilesoptions) ```typescript export interface ListFilesOptions { /** * The full path to the directory to list files for. * * @since 5.3.0 */ path: string; /** * The maximum number of results to return. * * @since 5.3.0 * @default 1000 */ maxResults?: number; /** * The page token, returned by a previous call to this method. * If provided, listing is resumed from the previous position. * * @since 5.3.0 */ pageToken?: string; } ``` ### `ListFilesResult` [Section titled “ListFilesResult”](#listfilesresult) ```typescript export interface ListFilesResult { /** * The list of files in the directory. * * @since 5.3.0 */ items: StorageReference[]; /** * If set, there might be more results for this list. * Use this token to resume the list. * * @since 5.3.0 */ nextPageToken?: string; } ``` ### `UpdateMetadataOptions` [Section titled “UpdateMetadataOptions”](#updatemetadataoptions) ```typescript export interface UpdateMetadataOptions { /** * The full path to the file to update the metadata for, including the file name. * * @since 5.3.0 */ path: string; /** * The metadata to update. * * @since 5.3.0 */ metadata: SettableMetadata; } ``` ### `UploadFileOptions` [Section titled “UploadFileOptions”](#uploadfileoptions) ```typescript export interface UploadFileOptions { /** * The data to upload. * * Only available for Web. * * @since 5.3.0 */ blob?: Blob; /** * The full path where data should be uploaded, including the file name. * * @since 5.3.0 * @example 'mountains.png' * @example 'images/mountains.png' */ path: string; /** * The uri to the file to upload. * * Only available for Android and iOS. * * @since 5.3.0 * @example 'content://com.google.android.apps.photos.contentprovider/-1/1/content://media/external/images/media/1000000214/ORIGINAL/NONE/image/.png/mountains' * @example 'file:///var/mobile/Containers/Data/Application/E397A70D-67E4-4258-236E-W1D9E12111D4/Library/Caches/092F8464-DE60-40B3-8A23-EB83160D9F9F/mountains.png' */ uri?: string; /** * The metadata to set for the file. * * @since 5.4.0 */ metadata?: UploadMetadata; } ``` ### `UploadFileCallback` [Section titled “UploadFileCallback”](#uploadfilecallback) ```typescript export type UploadFileCallback = (event: UploadFileCallbackEvent | null, error: any) => void; ``` ### `CallbackId` [Section titled “CallbackId”](#callbackid) ```typescript export type CallbackId = string; ``` ### `UseEmulatorOptions` [Section titled “UseEmulatorOptions”](#useemulatoroptions) ```typescript export interface UseEmulatorOptions { /** * The emulator host without any port or scheme. * * Note when using a Android Emulator device: 10.0.2.2 is the special IP address to connect to the 'localhost' of the host computer. * * @since 6.1.0 * @example "127.0.0.1" */ host: string; /** * The emulator port. * * @since 6.1.0 * @default 9199 * @example 9199 */ port?: number; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-flash > Capacitor Flash Plugin for controlling device flashlight/torch. ## Overview [Section titled “Overview”](#overview) Capacitor Flash Plugin for controlling device flashlight/torch. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `isAvailable` - Checks if flashlight is available on the device. * `switchOn` - Turns the flashlight on. * `switchOff` - Turns the flashlight off. * `isSwitchedOn` - Checks if the flashlight is currently turned on or off. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------ | ------------------------------------------------------- | | `isAvailable` | Checks if flashlight is available on the device. | | `switchOn` | Turns the flashlight on. | | `switchOff` | Turns the flashlight off. | | `isSwitchedOn` | Checks if the flashlight is currently turned on or off. | | `toggle` | Toggle the flashlight on or off. | | `getPluginVersion` | Get the native Capacitor plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-flash](https://github.com/Cap-go/capacitor-flash/). # Getting Started > Install @capgo/capacitor-flash and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-flash bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { CapacitorFlash } from '@capgo/capacitor-flash'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `isAvailable` [Section titled “isAvailable”](#isavailable) Checks if flashlight is available on the device. ```typescript import { CapacitorFlash } from '@capgo/capacitor-flash'; const { value } = await CapacitorFlash.isAvailable(); if (value) { console.log('Flashlight is available'); } ``` ### `switchOn` [Section titled “switchOn”](#switchon) Turns the flashlight on. ```typescript import { CapacitorFlash } from '@capgo/capacitor-flash'; // Turn on at full brightness await CapacitorFlash.switchOn({ intensity: 1.0 }); // Turn on at half brightness await CapacitorFlash.switchOn({ intensity: 0.5 }); ``` ### `switchOff` [Section titled “switchOff”](#switchoff) Turns the flashlight off. ```typescript import { CapacitorFlash } from '@capgo/capacitor-flash'; await CapacitorFlash.switchOff(); ``` ### `isSwitchedOn` [Section titled “isSwitchedOn”](#isswitchedon) Checks if the flashlight is currently turned on or off. ```typescript import { CapacitorFlash } from '@capgo/capacitor-flash'; const { value } = await CapacitorFlash.isSwitchedOn(); console.log('Flashlight is on:', value); ``` ### `toggle` [Section titled “toggle”](#toggle) Toggle the flashlight on or off. ```typescript import { CapacitorFlash } from '@capgo/capacitor-flash'; const { value } = await CapacitorFlash.toggle(); console.log('Flashlight toggled, now on:', value); ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-gtm > The main interface for the Google Tag Manager plugin. ## Overview [Section titled “Overview”](#overview) The main interface for the Google Tag Manager plugin. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `initialize` - Initializes Google Tag Manager with the specified container ID. * `push` - Pushes an event to the Google Tag Manager dataLayer. * `setUserProperty` - Sets a user property in the Google Tag Manager dataLayer. * `getValue` - Gets a value from the Google Tag Manager dataLayer. Searches through the dataLayer for the most recent value of the specified key. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------- | | `initialize` | Initializes Google Tag Manager with the specified container ID. | | `push` | Pushes an event to the Google Tag Manager dataLayer. | | `setUserProperty` | Sets a user property in the Google Tag Manager dataLayer. | | `getValue` | Gets a value from the Google Tag Manager dataLayer. Searches through the dataLayer for the most recent value of the specified key. | | `reset` | Resets the Google Tag Manager instance and clears all data. This will remove all data from the dataLayer and require re-initialization. | | `getPluginVersion` | Get the native Capacitor plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-gtm](https://github.com/Cap-go/capacitor-gtm/). # Getting Started > Install @capgo/capacitor-gtm and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-gtm bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { GoogleTagManager } from '@capgo/capacitor-gtm'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `initialize` [Section titled “initialize”](#initialize) Initializes Google Tag Manager with the specified container ID. ```typescript import { GoogleTagManager } from '@capgo/capacitor-gtm'; await GoogleTagManager.initialize({} as { containerId: string; timeout?: number }); ``` ### `push` [Section titled “push”](#push) Pushes an event to the Google Tag Manager dataLayer. ```typescript import { GoogleTagManager } from '@capgo/capacitor-gtm'; await GoogleTagManager.push({ event: 'purchase', parameters: { value: 99.99, currency: 'USD' } }); ``` ### `setUserProperty` [Section titled “setUserProperty”](#setuserproperty) Sets a user property in the Google Tag Manager dataLayer. ```typescript import { GoogleTagManager } from '@capgo/capacitor-gtm'; await GoogleTagManager.setUserProperty({ key: 'user_type', value: 'premium' }); ``` ### `getValue` [Section titled “getValue”](#getvalue) Gets a value from the Google Tag Manager dataLayer. Searches through the dataLayer for the most recent value of the specified key. ```typescript import { GoogleTagManager } from '@capgo/capacitor-gtm'; await GoogleTagManager.getValue({} as { key: string }); ``` ### `reset` [Section titled “reset”](#reset) Resets the Google Tag Manager instance and clears all data. This will remove all data from the dataLayer and require re-initialization. ```typescript import { GoogleTagManager } from '@capgo/capacitor-gtm'; await GoogleTagManager.reset(); ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-health > Capacitor plugin to interact with data from Apple HealthKit and Health Connect. ## Overview [Section titled “Overview”](#overview) Capacitor plugin to interact with data from Apple HealthKit and Health Connect. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `isAvailable` - Returns whether the current platform supports the native health SDK. * `requestAuthorization` - Requests read/write access to the provided data types. * `checkAuthorization` - Checks authorization status for the provided data types without prompting the user. * `readSamples` - Reads samples for the given data type within the specified time frame. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `isAvailable` | Returns whether the current platform supports the native health SDK. | | `requestAuthorization` | Requests read/write access to the provided data types. | | `checkAuthorization` | Checks authorization status for the provided data types without prompting the user. | | `readSamples` | Reads samples for the given data type within the specified time frame. | | `saveSample` | Writes a single sample to the native health store. | | `getPluginVersion` | Get the native Capacitor plugin version. | | `openHealthConnectSettings` | Opens the Health Connect settings screen (Android only). On iOS, this method does nothing. | | `showPrivacyPolicy` | Shows the app’s privacy policy for Health Connect (Android only). On iOS, this method does nothing. | | `queryWorkouts` | Queries workout sessions from the native health store. Supported on iOS (HealthKit) and Android (Health Connect). | | `queryAggregated` | Queries aggregated health data from the native health store. Aggregates data into time buckets (hour, day, week, month) with operations like sum, average, min, or max. This is more efficient than fetching individual samples for large date ranges. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-health](https://github.com/Cap-go/capacitor-health/). # Getting Started > Install @capgo/capacitor-health and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-health bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { Health } from '@capgo/capacitor-health'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `isAvailable` [Section titled “isAvailable”](#isavailable) Returns whether the current platform supports the native health SDK. ```typescript import { Health } from '@capgo/capacitor-health'; await Health.isAvailable(); ``` ### `requestAuthorization` [Section titled “requestAuthorization”](#requestauthorization) Requests read/write access to the provided data types. ```typescript import { Health } from '@capgo/capacitor-health'; await Health.requestAuthorization({} as AuthorizationOptions); ``` ### `checkAuthorization` [Section titled “checkAuthorization”](#checkauthorization) Checks authorization status for the provided data types without prompting the user. ```typescript import { Health } from '@capgo/capacitor-health'; await Health.checkAuthorization({} as AuthorizationOptions); ``` ### `readSamples` [Section titled “readSamples”](#readsamples) Reads samples for the given data type within the specified time frame. ```typescript import { Health } from '@capgo/capacitor-health'; await Health.readSamples({} as QueryOptions); ``` ### `saveSample` [Section titled “saveSample”](#savesample) Writes a single sample to the native health store. ```typescript import { Health } from '@capgo/capacitor-health'; await Health.saveSample({} as WriteSampleOptions); ``` ### `openHealthConnectSettings` [Section titled “openHealthConnectSettings”](#openhealthconnectsettings) Opens the Health Connect settings screen (Android only). On iOS, this method does nothing. Use this to direct users to manage their Health Connect permissions or to install Health Connect if not available. ```typescript import { Health } from '@capgo/capacitor-health'; await Health.openHealthConnectSettings(); ``` ### `showPrivacyPolicy` [Section titled “showPrivacyPolicy”](#showprivacypolicy) Shows the app’s privacy policy for Health Connect (Android only). On iOS, this method does nothing. This displays the same privacy policy screen that Health Connect shows when the user taps “Privacy policy” in the permissions dialog. The privacy policy URL can be configured by adding a string resource named “health\_connect\_privacy\_policy\_url” in your app’s strings.xml, or by placing an HTML file at www/privacypolicy.html in your assets. ```typescript import { Health } from '@capgo/capacitor-health'; await Health.showPrivacyPolicy(); ``` ### `queryWorkouts` [Section titled “queryWorkouts”](#queryworkouts) Queries workout sessions from the native health store. Supported on iOS (HealthKit) and Android (Health Connect). ```typescript import { Health } from '@capgo/capacitor-health'; await Health.queryWorkouts({} as QueryWorkoutsOptions); ``` ### `queryAggregated` [Section titled “queryAggregated”](#queryaggregated) Queries aggregated health data from the native health store. Aggregates data into time buckets (hour, day, week, month) with operations like sum, average, min, or max. This is more efficient than fetching individual samples for large date ranges. Supported on iOS (HealthKit) and Android (Health Connect). ```typescript import { Health } from '@capgo/capacitor-health'; await Health.queryAggregated({} as QueryAggregatedOptions); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `AvailabilityResult` [Section titled “AvailabilityResult”](#availabilityresult) ```typescript export interface AvailabilityResult { available: boolean; /** Platform specific details (for debugging/diagnostics). */ platform?: 'ios' | 'android' | 'web'; reason?: string; } ``` ### `AuthorizationOptions` [Section titled “AuthorizationOptions”](#authorizationoptions) ```typescript export interface AuthorizationOptions { /** Data types that should be readable after authorization. */ read?: HealthDataType[]; /** Data types that should be writable after authorization. */ write?: HealthDataType[]; } ``` ### `AuthorizationStatus` [Section titled “AuthorizationStatus”](#authorizationstatus) ```typescript export interface AuthorizationStatus { readAuthorized: HealthDataType[]; readDenied: HealthDataType[]; writeAuthorized: HealthDataType[]; writeDenied: HealthDataType[]; } ``` ### `QueryOptions` [Section titled “QueryOptions”](#queryoptions) ```typescript export interface QueryOptions { /** The type of data to retrieve from the health store. */ dataType: HealthDataType; /** Inclusive ISO 8601 start date (defaults to now - 1 day). */ startDate?: string; /** Exclusive ISO 8601 end date (defaults to now). */ endDate?: string; /** Maximum number of samples to return (defaults to 100). */ limit?: number; /** Return results sorted ascending by start date (defaults to false). */ ascending?: boolean; } ``` ### `ReadSamplesResult` [Section titled “ReadSamplesResult”](#readsamplesresult) ```typescript export interface ReadSamplesResult { samples: HealthSample[]; } ``` ### `WriteSampleOptions` [Section titled “WriteSampleOptions”](#writesampleoptions) ```typescript export interface WriteSampleOptions { dataType: HealthDataType; value: number; /** * Optional unit override. If omitted, the default unit for the data type is used * (count for `steps`, meter for `distance`, kilocalorie for `calories`, bpm for `heartRate`, kilogram for `weight`). */ unit?: HealthUnit; /** ISO 8601 start date for the sample. Defaults to now. */ startDate?: string; /** ISO 8601 end date for the sample. Defaults to startDate. */ endDate?: string; /** Metadata key-value pairs forwarded to the native APIs where supported. */ metadata?: Record; /** For blood pressure data, the systolic value in mmHg. Required when dataType is 'bloodPressure'. */ systolic?: number; /** For blood pressure data, the diastolic value in mmHg. Required when dataType is 'bloodPressure'. */ diastolic?: number; } ``` ### `QueryWorkoutsOptions` [Section titled “QueryWorkoutsOptions”](#queryworkoutsoptions) ```typescript export interface QueryWorkoutsOptions { /** Optional workout type filter. If omitted, all workout types are returned. */ workoutType?: WorkoutType; /** Inclusive ISO 8601 start date (defaults to now - 1 day). */ startDate?: string; /** Exclusive ISO 8601 end date (defaults to now). */ endDate?: string; /** Maximum number of workouts to return (defaults to 100). */ limit?: number; /** Return results sorted ascending by start date (defaults to false). */ ascending?: boolean; /** * Anchor for pagination. Use the anchor returned from a previous query to continue from that point. * On iOS, this is the ISO 8601 cursor returned by the previous query. On Android, this uses * Health Connect's pageToken. * Omit this parameter to start from the beginning. */ anchor?: string; } ``` ### `QueryWorkoutsResult` [Section titled “QueryWorkoutsResult”](#queryworkoutsresult) ```typescript export interface QueryWorkoutsResult { workouts: Workout[]; /** * Anchor for the next page of results. Pass this value as the anchor parameter in the next query * to continue pagination. If undefined or null, there are no more results. */ anchor?: string; } ``` ### `QueryAggregatedOptions` [Section titled “QueryAggregatedOptions”](#queryaggregatedoptions) ```typescript export interface QueryAggregatedOptions { /** The type of data to aggregate from the health store. */ dataType: HealthDataType; /** Inclusive ISO 8601 start date (defaults to now - 1 day). */ startDate?: string; /** Exclusive ISO 8601 end date (defaults to now). */ endDate?: string; /** Time bucket for aggregation (defaults to 'day'). */ bucket?: BucketType; /** Aggregation operation to perform (defaults to 'sum'). */ aggregation?: AggregationType; } ``` ### `QueryAggregatedResult` [Section titled “QueryAggregatedResult”](#queryaggregatedresult) ```typescript export interface QueryAggregatedResult { samples: AggregatedSample[]; } ``` ### `HealthDataType` [Section titled “HealthDataType”](#healthdatatype) ```typescript export type HealthDataType = | 'steps' | 'distance' | 'calories' | 'heartRate' | 'weight' | 'sleep' | 'respiratoryRate' | 'oxygenSaturation' | 'restingHeartRate' | 'heartRateVariability' | 'bloodPressure' | 'bloodGlucose' | 'bodyTemperature' | 'height' | 'flightsClimbed' | 'exerciseTime' | 'distanceCycling' | 'bodyFat' | 'basalBodyTemperature' | 'basalCalories' | 'totalCalories' | 'mindfulness' | 'workouts'; ``` ### `HealthSample` [Section titled “HealthSample”](#healthsample) ```typescript export interface HealthSample { dataType: HealthDataType; value: number; unit: HealthUnit; startDate: string; endDate: string; sourceName?: string; sourceId?: string; /** Platform-specific unique identifier (HealthKit UUID on iOS, Health Connect metadata ID on Android). */ platformId?: string; /** For sleep data, indicates the sleep state (e.g., 'asleep', 'awake', 'rem', 'deep', 'light'). */ sleepState?: SleepState; /** For blood pressure data, the systolic value in mmHg. */ systolic?: number; /** For blood pressure data, the diastolic value in mmHg. */ diastolic?: number; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-home-indicator > Capacitor Home Indicator Plugin for controlling the iOS home indicator visibility. The home indicator is the horizontal bar at the bottom of iOS devices without a physical home button. ## Overview [Section titled “Overview”](#overview) Capacitor Home Indicator Plugin for controlling the iOS home indicator visibility. The home indicator is the horizontal bar at the bottom of iOS devices without a physical home button. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `hide` - Hide the home indicator at the bottom of the screen. * `show` - Show the home indicator at the bottom of the screen. * `isHidden` - Check whether the home indicator is currently hidden. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------ | ----------------------------------------------------- | | `hide` | Hide the home indicator at the bottom of the screen. | | `show` | Show the home indicator at the bottom of the screen. | | `isHidden` | Check whether the home indicator is currently hidden. | | `getPluginVersion` | Get the native Capacitor plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-home-indicator](https://github.com/Cap-go/capacitor-home-indicator/). # Getting Started > Install @capgo/capacitor-home-indicator and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-home-indicator bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { HomeIndicator } from '@capgo/capacitor-home-indicator'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `hide` [Section titled “hide”](#hide) Hide the home indicator at the bottom of the screen. This visually hides the iOS home indicator bar, providing a more immersive full-screen experience. Users can still swipe up to access home, but the indicator will not be visible until they start the gesture. iOS only. Has no effect on Android or web. ```typescript import { HomeIndicator } from '@capgo/capacitor-home-indicator'; await HomeIndicator.hide(); ``` ### `show` [Section titled “show”](#show) Show the home indicator at the bottom of the screen. This restores the default iOS home indicator visibility, making it always visible to the user. This is the default behavior. iOS only. Has no effect on Android or web. ```typescript import { HomeIndicator } from '@capgo/capacitor-home-indicator'; await HomeIndicator.show(); ``` ### `isHidden` [Section titled “isHidden”](#ishidden) Check whether the home indicator is currently hidden. Returns the current visibility state of the iOS home indicator. ```typescript import { HomeIndicator } from '@capgo/capacitor-home-indicator'; const { hidden } = await HomeIndicator.isHidden(); if (hidden) { console.log('Home indicator is hidden'); } else { console.log('Home indicator is visible'); } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-ibeacon > Capacitor iBeacon Plugin - Proximity detection and beacon region monitoring. ## Overview [Section titled “Overview”](#overview) Capacitor iBeacon Plugin - Proximity detection and beacon region monitoring. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `startMonitoringForRegion` - Start monitoring for a beacon region. Triggers events when entering/exiting the region. * `stopMonitoringForRegion` - Stop monitoring for a beacon region. * `startRangingBeaconsInRegion` - Start ranging beacons in a region. Provides continuous distance updates. * `stopRangingBeaconsInRegion` - Stop ranging beacons in a region. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `startMonitoringForRegion` | Start monitoring for a beacon region. Triggers events when entering/exiting the region. | | `stopMonitoringForRegion` | Stop monitoring for a beacon region. | | `startRangingBeaconsInRegion` | Start ranging beacons in a region. Provides continuous distance updates. | | `stopRangingBeaconsInRegion` | Stop ranging beacons in a region. | | `startAdvertising` | Start advertising the device as an iBeacon (iOS only). | | `stopAdvertising` | Stop advertising the device as an iBeacon (iOS only). | | `requestWhenInUseAuthorization` | Request “When In Use” location authorization (required for ranging/monitoring). | | `requestAlwaysAuthorization` | Request “Always” location authorization (required for background monitoring). | | `getAuthorizationStatus` | Get current location authorization status. | | `isBluetoothEnabled` | Check if Bluetooth is enabled on the device. | | `isRangingAvailable` | Check if ranging is available on the device. | | `enableARMAFilter` | Enable ARMA filtering for distance calculations (Android only). | | `getPluginVersion` | Get the native Capacitor plugin version. | | `enableBackgroundMode` | Enable or disable background beacon scanning mode (Android only). This enables a foreground service for reliable background beacon detection. Must be called after requesting “Always” location authorization. | | `setBackgroundScanPeriod` | Configure background scan periods (Android only). Controls how often and how long the device scans for beacons when in background. | | `addListener` | Listen for beacon ranging events. | | `addListener` | Listen for region enter events. | | `addListener` | Listen for region exit events. | | `addListener` | Listen for region state determination events. | | `addListener` | Listen for monitoring failure events. | | `removeAllListeners` | Remove all listeners for this plugin. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-ibeacon](https://github.com/Cap-go/capacitor-ibeacon/). # Getting Started > Install @capgo/capacitor-ibeacon and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-ibeacon bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { CapacitorIbeacon } from '@capgo/capacitor-ibeacon'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `startMonitoringForRegion` [Section titled “startMonitoringForRegion”](#startmonitoringforregion) Start monitoring for a beacon region. Triggers events when entering/exiting the region. ```typescript import { CapacitorIbeacon } from '@capgo/capacitor-ibeacon'; await CapacitorIbeacon.startMonitoringForRegion({ identifier: 'MyBeaconRegion', uuid: 'B9407F30-F5F8-466E-AFF9-25556B57FE6D' }); ``` ### `stopMonitoringForRegion` [Section titled “stopMonitoringForRegion”](#stopmonitoringforregion) Stop monitoring for a beacon region. ```typescript import { CapacitorIbeacon } from '@capgo/capacitor-ibeacon'; await CapacitorIbeacon.stopMonitoringForRegion({ identifier: 'MyBeaconRegion', uuid: 'B9407F30-F5F8-466E-AFF9-25556B57FE6D' }); ``` ### `startRangingBeaconsInRegion` [Section titled “startRangingBeaconsInRegion”](#startrangingbeaconsinregion) Start ranging beacons in a region. Provides continuous distance updates. ```typescript import { CapacitorIbeacon } from '@capgo/capacitor-ibeacon'; await CapacitorIbeacon.startRangingBeaconsInRegion({ identifier: 'MyBeaconRegion', uuid: 'B9407F30-F5F8-466E-AFF9-25556B57FE6D' }); ``` ### `stopRangingBeaconsInRegion` [Section titled “stopRangingBeaconsInRegion”](#stoprangingbeaconsinregion) Stop ranging beacons in a region. ```typescript import { CapacitorIbeacon } from '@capgo/capacitor-ibeacon'; await CapacitorIbeacon.stopRangingBeaconsInRegion({ identifier: 'MyBeaconRegion', uuid: 'B9407F30-F5F8-466E-AFF9-25556B57FE6D' }); ``` ### `startAdvertising` [Section titled “startAdvertising”](#startadvertising) Start advertising the device as an iBeacon (iOS only). ```typescript import { CapacitorIbeacon } from '@capgo/capacitor-ibeacon'; await CapacitorIbeacon.startAdvertising({ uuid: 'B9407F30-F5F8-466E-AFF9-25556B57FE6D', major: 1, minor: 2, identifier: 'MyBeacon' }); ``` ### `stopAdvertising` [Section titled “stopAdvertising”](#stopadvertising) Stop advertising the device as an iBeacon (iOS only). ```typescript import { CapacitorIbeacon } from '@capgo/capacitor-ibeacon'; await CapacitorIbeacon.stopAdvertising(); ``` ### `requestWhenInUseAuthorization` [Section titled “requestWhenInUseAuthorization”](#requestwheninuseauthorization) Request “When In Use” location authorization (required for ranging/monitoring). ```typescript import { CapacitorIbeacon } from '@capgo/capacitor-ibeacon'; const { status } = await CapacitorIbeacon.requestWhenInUseAuthorization(); console.log('Authorization status:', status); ``` ### `requestAlwaysAuthorization` [Section titled “requestAlwaysAuthorization”](#requestalwaysauthorization) Request “Always” location authorization (required for background monitoring). ```typescript import { CapacitorIbeacon } from '@capgo/capacitor-ibeacon'; const { status } = await CapacitorIbeacon.requestAlwaysAuthorization(); console.log('Authorization status:', status); ``` ### `getAuthorizationStatus` [Section titled “getAuthorizationStatus”](#getauthorizationstatus) Get current location authorization status. ```typescript import { CapacitorIbeacon } from '@capgo/capacitor-ibeacon'; const { status } = await CapacitorIbeacon.getAuthorizationStatus(); console.log('Current status:', status); ``` ### `isBluetoothEnabled` [Section titled “isBluetoothEnabled”](#isbluetoothenabled) Check if Bluetooth is enabled on the device. ```typescript import { CapacitorIbeacon } from '@capgo/capacitor-ibeacon'; const { enabled } = await CapacitorIbeacon.isBluetoothEnabled(); if (!enabled) { console.log('Please enable Bluetooth'); } ``` ### `isRangingAvailable` [Section titled “isRangingAvailable”](#israngingavailable) Check if ranging is available on the device. ```typescript import { CapacitorIbeacon } from '@capgo/capacitor-ibeacon'; const { available } = await CapacitorIbeacon.isRangingAvailable(); if (available) { console.log('Ranging is supported'); } ``` ### `enableARMAFilter` [Section titled “enableARMAFilter”](#enablearmafilter) Enable ARMA filtering for distance calculations (Android only). ```typescript import { CapacitorIbeacon } from '@capgo/capacitor-ibeacon'; await CapacitorIbeacon.enableARMAFilter({ enabled: true }); ``` ### `enableBackgroundMode` [Section titled “enableBackgroundMode”](#enablebackgroundmode) Enable or disable background beacon scanning mode (Android only). This enables a foreground service for reliable background beacon detection. Must be called after requesting “Always” location authorization. ```typescript import { CapacitorIbeacon } from '@capgo/capacitor-ibeacon'; // Enable background mode for beacon scanning await CapacitorIbeacon.enableBackgroundMode({ enabled: true }); // Disable background mode await CapacitorIbeacon.enableBackgroundMode({ enabled: false }); ``` ### `setBackgroundScanPeriod` [Section titled “setBackgroundScanPeriod”](#setbackgroundscanperiod) Configure background scan periods (Android only). Controls how often and how long the device scans for beacons when in background. ```typescript import { CapacitorIbeacon } from '@capgo/capacitor-ibeacon'; // Set background scan to 10 seconds every 30 seconds await CapacitorIbeacon.setBackgroundScanPeriod({ scanPeriod: 10000, // 10 seconds of scanning betweenScanPeriod: 30000 // 30 seconds between scans }); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `BeaconRegion` [Section titled “BeaconRegion”](#beaconregion) Beacon region definition for monitoring and ranging. ```typescript export interface BeaconRegion { /** * Unique identifier for this region. */ identifier: string; /** * UUID of the beacon(s) to detect. */ uuid: string; /** * Major value for filtering (optional). */ major?: number; /** * Minor value for filtering (optional). */ minor?: number; /** * Notify when device enters region (iOS only). */ notifyEntryStateOnDisplay?: boolean; /** * Enable Android background mode for this monitoring/ranging call. * When true, the plugin will keep scanning in background using a foreground service. */ enableBackgroundMode?: boolean; } ``` ### `BeaconAdvertisingOptions` [Section titled “BeaconAdvertisingOptions”](#beaconadvertisingoptions) Beacon advertising options for transmitting as an iBeacon (iOS only). ```typescript export interface BeaconAdvertisingOptions { /** * UUID to advertise. */ uuid: string; /** * Major value (0-65535). */ major: number; /** * Minor value (0-65535). */ minor: number; /** * Identifier for the advertising beacon. */ identifier: string; /** * Measured power (RSSI at 1 meter). Optional, defaults to -59. */ measuredPower?: number; } ``` ### `BackgroundScanPeriodOptions` [Section titled “BackgroundScanPeriodOptions”](#backgroundscanperiodoptions) Background scan period configuration options (Android only). ```typescript export interface BackgroundScanPeriodOptions { /** * Duration of each scan period in milliseconds. * Default: 10000 (10 seconds) */ scanPeriod?: number; /** * Duration between scan periods in milliseconds. * Default: 15000 (15 seconds) */ betweenScanPeriod?: number; } ``` ### `RangingEventData` [Section titled “RangingEventData”](#rangingeventdata) Event data when beacons are ranged. ```typescript export interface RangingEventData { /** * Region that was ranged. */ region: BeaconRegion; /** * Array of detected beacons. */ beacons: Beacon[]; } ``` ### `MonitoringEventData` [Section titled “MonitoringEventData”](#monitoringeventdata) Event data when entering or exiting a region. ```typescript export interface MonitoringEventData { /** * Region that triggered the event. */ region: BeaconRegion; /** * Event state: 'enter' or 'exit'. */ state: 'enter' | 'exit'; } ``` ### `Beacon` [Section titled “Beacon”](#beacon) Detected beacon information. ```typescript export interface Beacon { /** * Beacon UUID. */ uuid: string; /** * Major value. */ major: number; /** * Minor value. */ minor: number; /** * RSSI (Received Signal Strength Indicator). */ rssi: number; /** * Proximity: 'immediate', 'near', 'far', or 'unknown'. */ proximity: 'immediate' | 'near' | 'far' | 'unknown'; /** * Estimated distance in meters. */ accuracy: number; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-in-app-review > Capacitor In-App Review Plugin interface for prompting users to submit app store ratings and reviews without leaving the app. ## Overview [Section titled “Overview”](#overview) Capacitor In-App Review Plugin interface for prompting users to submit app store ratings and reviews without leaving the app. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `requestReview` - Request an in-app review from the user. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------ | ---------------------------------------- | | `requestReview` | Request an in-app review from the user. | | `getPluginVersion` | Get the native Capacitor plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-in-app-review](https://github.com/Cap-go/capacitor-in-app-review/). # Getting Started > Install @capgo/capacitor-in-app-review and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-in-app-review bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { CapgoInAppReview } from '@capgo/capacitor-in-app-review'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `requestReview` [Section titled “requestReview”](#requestreview) Request an in-app review from the user. This method triggers the native in-app review dialog provided by the platform. On iOS, it uses SKStoreReviewController. On Android, it uses the Play In-App Review API. **Important Notes:** * The review dialog may not be displayed every time this method is called. Both Apple and Google have guidelines that limit how often the prompt can appear. * There is no guarantee that the user will see the review prompt. * The method resolves successfully even if the dialog was not shown. * Do not call this in response to a user action like a button tap. Instead, call it at natural points in your app’s user flow. ```typescript import { CapgoInAppReview } from '@capgo/capacitor-in-app-review'; // Request a review at an appropriate moment in your app await CapgoInAppReview.requestReview(); ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/inappbrowser > Capacitor plugin in app browser. ## Overview [Section titled “Overview”](#overview) Capacitor plugin in app browser. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `goBack` - Navigates back in the WebView’s history if possible. * `open` - Open url in a new window fullscreen, on android it use chrome custom tabs, on ios it use SFSafariViewController. * `clearCookies` - Clear cookies of url When `id` is omitted, applies to all open webviews. * `clearAllCookies` - Clear all cookies When `id` is omitted, applies to all open webviews. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `goBack` | Navigates back in the WebView’s history if possible. | | `open` | Open url in a new window fullscreen, on android it use chrome custom tabs, on ios it use SFSafariViewController. | | `clearCookies` | Clear cookies of url When `id` is omitted, applies to all open webviews. | | `clearAllCookies` | Clear all cookies When `id` is omitted, applies to all open webviews. | | `clearCache` | Clear cache When `id` is omitted, applies to all open webviews. | | `getCookies` | Get cookies for a specific URL. | | `close` | Close the webview. When `id` is omitted, closes the active webview. | | `hide` | Hide the webview without closing it. Use show() to bring it back. When `id` is omitted, targets the active webview. | | `show` | Show a previously hidden webview. When `id` is omitted, targets the active webview. | | `openWebView` | Open url in a new webview with toolbars, and enhanced capabilities, like camera access, file access, listen events, inject javascript, bi directional communication, etc. | | `executeScript` | Injects JavaScript code into the InAppBrowser window. When `id` is omitted, executes in all open webviews. | | `postMessage` | Sends an event to the webview (in-app browser). Listen in the page with `window.addEventListener('messageFromNative', listenerFunc)`. The `detail` payload must be JSON-serializable. When `id` is omitted, broadcasts to all open webviews. | | `takeScreenshot` | Captures the current webview viewport as a PNG screenshot. When `id` is omitted, targets the active webview. | | `setUrl` | Sets the URL of the webview. When `id` is omitted, targets the active webview. | | `addListener` | Listen for url change, only for openWebView. | | `addListener` | See the source definitions for current behavior. | | `addListener` | Listen for close click only for openWebView. | | `addListener` | Will be triggered when user clicks on confirm button when disclaimer is required, works with openWebView shareDisclaimer and closeModal. | | `addListener` | Fires when the webview sends an event back to the app. Use `window.mobileApp.postMessage(...)` in the page, and keep the payload JSON-serializable. | | `addListener` | Will be triggered whenever a screenshot is captured from the plugin API, the native screenshot button, or the injected JavaScript bridge. | | `addListener` | Will be triggered when page is loaded. | | `addListener` | Will be triggered when page load error. | | `addListener` | Will be triggered after native download handling saves a file locally. Enable this with `handleDownloads: true` when opening the webview. | | `addListener` | Will be triggered when native download handling fails. Enable this with `handleDownloads: true` when opening the webview. | | `addListener` | Will be triggered whenever a page opens a popup/new window. Use the returned popup id with `executeScript`, `postMessage`, `show`, `hide`, and `close`. | | `addListener` | Listen for proxied requests delegated by the native runtime. Prefer `addProxyHandler()` instead of calling this directly. | | `addListener` | Listen for JavaScript console output emitted by the managed page. Enable this with `captureConsoleLogs: true` when opening the webview. | | `handleProxyRequest` | Internal method used by `addProxyHandler()` to send a proxy decision back to native. Forward the original `phase` when replying to a manual `proxyRequest` listener. | | `removeAllListeners` | Remove all listeners for this plugin. | | `reload` | Reload the current web page. | | `updateDimensions` | Update the dimensions of the webview. Allows changing the size and position of the webview at runtime. When `id` is omitted, targets the active webview. | | `setEnabledSafeTopMargin` | Sets the enabled safe top margin of the webview at runtime. When `id` is omitted, targets the active webview. On Web, this method is a no-op and resolves without changing layout. | | `setEnabledSafeBottomMargin` | Sets the enabled safe bottom margin of the webview at runtime. When `id` is omitted, targets the active webview. On Web, this method is a no-op and resolves without changing layout. | | `openSecureWindow` | Opens a secure OAuth2 window. On web, return the redirected URL through a `BroadcastChannel`; on mobile, register a custom redirect URI in your app configuration. See the getting-started guide for the full HTML, Info.plist, and AndroidManifest examples. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-inappbrowser](https://github.com/Cap-go/capacitor-inappbrowser/). # Getting Started > Install @capgo/inappbrowser and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/inappbrowser bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { InAppBrowser } from '@capgo/inappbrowser'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `goBack` [Section titled “goBack”](#goback) Navigates back in the WebView’s history if possible ```typescript import { InAppBrowser } from '@capgo/inappbrowser'; await InAppBrowser.goBack(); ``` ### `open` [Section titled “open”](#open) Open url in a new window fullscreen, on android it use chrome custom tabs, on ios it use SFSafariViewController ```typescript import { InAppBrowser } from '@capgo/inappbrowser'; await InAppBrowser.open({} as OpenOptions); ``` ### `clearCookies` [Section titled “clearCookies”](#clearcookies) Clear cookies of url When `id` is omitted, applies to all open webviews. ```typescript import { InAppBrowser } from '@capgo/inappbrowser'; await InAppBrowser.clearCookies({} as ClearCookieOptions); ``` ### `clearAllCookies` [Section titled “clearAllCookies”](#clearallcookies) Clear all cookies When `id` is omitted, applies to all open webviews. ```typescript import { InAppBrowser } from '@capgo/inappbrowser'; await InAppBrowser.clearAllCookies(); ``` ### `clearCache` [Section titled “clearCache”](#clearcache) Clear cache When `id` is omitted, applies to all open webviews. ```typescript import { InAppBrowser } from '@capgo/inappbrowser'; await InAppBrowser.clearCache(); ``` ### `getCookies` [Section titled “getCookies”](#getcookies) Get cookies for a specific URL. ```typescript import { InAppBrowser } from '@capgo/inappbrowser'; await InAppBrowser.getCookies({} as GetCookieOptions); ``` ### `close` [Section titled “close”](#close) Close the webview. When `id` is omitted, closes the active webview. ```typescript import { InAppBrowser } from '@capgo/inappbrowser'; await InAppBrowser.close(); ``` ### `hide` [Section titled “hide”](#hide) Hide the webview without closing it. Use show() to bring it back. When `id` is omitted, targets the active webview. ```typescript import { InAppBrowser } from '@capgo/inappbrowser'; await InAppBrowser.hide(); ``` ### `show` [Section titled “show”](#show) Show a previously hidden webview. When `id` is omitted, targets the active webview. ```typescript import { InAppBrowser } from '@capgo/inappbrowser'; await InAppBrowser.show(); ``` ### `openWebView` [Section titled “openWebView”](#openwebview) Open url in a new webview with toolbars, and enhanced capabilities, like camera access, file access, listen events, inject javascript, bi directional communication, etc. JavaScript Interface: When you open a webview with this method, a JavaScript interface is automatically injected that provides: * `window.mobileApp.close()`: Closes the webview from JavaScript * `window.mobileApp.postMessage({detail: {message: "myMessage"}})`: Sends a message from the webview to the app, detail object is the data you want to send to the webview * `window.mobileApp.takeScreenshot()` when `allowScreenshotsFromWebPage` is true Promise timing differs by platform when `isPresentAfterPageLoad` is used. Android resolves with `{ id }` after the dialog is ready to control, while iOS resolves with `{ id }` immediately after creating the native webview. ```typescript import { InAppBrowser } from '@capgo/inappbrowser'; await InAppBrowser.openWebView({} as OpenWebViewOptions); ``` ### `executeScript` [Section titled “executeScript”](#executescript) Injects JavaScript code into the InAppBrowser window. When `id` is omitted, executes in all open webviews. ```typescript import { InAppBrowser } from '@capgo/inappbrowser'; await InAppBrowser.executeScript({} as { code: string; id?: string }); ``` ### `postMessage` [Section titled “postMessage”](#postmessage) Sends an event to the webview (in-app browser). In the webview JavaScript, listen for it with `window.addEventListener('messageFromNative', listenerFunc)`. `detail` is the payload sent to the webview. Because it crosses the Capacitor bridge, it must be JSON-serializable. When `id` is omitted, broadcasts to all open webviews. ```typescript import { InAppBrowser } from '@capgo/inappbrowser'; await InAppBrowser.postMessage({} as { detail: Record; id?: string }); ``` ### `takeScreenshot` [Section titled “takeScreenshot”](#takescreenshot) Captures the current webview viewport as a PNG screenshot. When `id` is omitted, targets the active webview. ```typescript import { InAppBrowser } from '@capgo/inappbrowser'; await InAppBrowser.takeScreenshot(); ``` ### `setUrl` [Section titled “setUrl”](#seturl) Sets the URL of the webview. When `id` is omitted, targets the active webview. ```typescript import { InAppBrowser } from '@capgo/inappbrowser'; await InAppBrowser.setUrl({} as { url: string; id?: string }); ``` ### `handleProxyRequest` [Section titled “handleProxyRequest”](#handleproxyrequest) Internal method used by `addProxyHandler()` to send a proxy decision back to native. Forward the original `phase` when replying to a manual `proxyRequest` listener. ```typescript import { InAppBrowser } from '@capgo/inappbrowser'; await InAppBrowser.handleProxyRequest({} as { requestId: string; decision?: ProxyDecision | null; response?: ProxyResponse | null; webviewId?: string; phase?: 'outbound' | 'inbound'; }); ``` ### `reload` [Section titled “reload”](#reload) Reload the current web page. ```typescript import { InAppBrowser } from '@capgo/inappbrowser'; await InAppBrowser.reload(); ``` ### `updateDimensions` [Section titled “updateDimensions”](#updatedimensions) Update the dimensions of the webview. Allows changing the size and position of the webview at runtime. When `id` is omitted, targets the active webview. ```typescript import { InAppBrowser } from '@capgo/inappbrowser'; await InAppBrowser.updateDimensions({} as DimensionOptions & { id?: string }); ``` ### `setEnabledSafeTopMargin` [Section titled “setEnabledSafeTopMargin”](#setenabledsafetopmargin) Sets the enabled safe top margin of the webview at runtime. When `id` is omitted, targets the active webview. On Web, this method is a no-op and resolves without changing layout. ```typescript import { InAppBrowser } from '@capgo/inappbrowser'; await InAppBrowser.setEnabledSafeTopMargin({} as { enabled: boolean; id?: string }); ``` ### `setEnabledSafeBottomMargin` [Section titled “setEnabledSafeBottomMargin”](#setenabledsafebottommargin) Sets the enabled safe bottom margin of the webview at runtime. When `id` is omitted, targets the active webview. On Web, this method is a no-op and resolves without changing layout. ```typescript import { InAppBrowser } from '@capgo/inappbrowser'; await InAppBrowser.setEnabledSafeBottomMargin({} as { enabled: boolean; id?: string }); ``` ### `openSecureWindow` [Section titled “openSecureWindow”](#opensecurewindow) Opens a secured window for OAuth2 authentication. For web, you should have the code in the redirected page to use a broadcast channel to send the redirected url to the app Something like: ```html ``` For mobile, you should have a redirect uri that opens the app, something like: `myapp://oauth_callback/` And make sure to register it in the app’s info.plist: ```xml CFBundleURLTypes CFBundleURLSchemes myapp ``` And in the AndroidManifest.xml file: ```xml ``` ```typescript import { InAppBrowser } from '@capgo/inappbrowser'; await InAppBrowser.openSecureWindow({} as OpenSecureWindowOptions); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `OpenOptions` [Section titled “OpenOptions”](#openoptions) ```typescript export interface OpenOptions { /** * Target URL to load. * @since 0.1.0 */ url: string; /** * if true, the browser will be presented after the page is loaded, if false, the browser will be presented immediately. * @since 0.1.0 */ isPresentAfterPageLoad?: boolean; /** * if true the deeplink will not be opened, if false the deeplink will be opened when clicked on the link * @since 0.1.0 */ preventDeeplink?: boolean; // --- Chrome Custom Tab customization (Android only, ignored on iOS) --- /** * Toolbar background color in hex format (e.g., "#1A1A2E"). * Applied to both light and dark color schemes. * Also sets the navigation bar color to match. * **Android only** — ignored on iOS. * @since 8.2.0 */ toolbarColor?: string; /** * Whether the URL bar should auto-hide when the user scrolls down. * The bar reappears on any upward scroll. * **Android only** — ignored on iOS. * @default false * @since 8.2.0 */ urlBarHidingEnabled?: boolean; /** * Show the page's HTML in the toolbar instead of the raw URL. * The true URL is still visible when the user taps the title area. * **Android only** — ignored on iOS. * @default false * @since 8.2.0 */ showTitle?: boolean; /** * Replace the default "X" close icon with a back arrow. * Makes the Custom Tab feel like a native navigation push rather than a modal overlay. * **Android only** — ignored on iOS. * @default false * @since 8.2.0 */ showArrow?: boolean; /** * Remove the share action from the overflow menu. * **Android only** — ignored on iOS. * @default false * @since 8.2.0 */ disableShare?: boolean; /** * Hide the bookmark star icon in the overflow menu. * Uses an undocumented Chromium intent extra — may stop working on future Chrome updates. * **Android only** — ignored on iOS. * @default false * @since 8.2.0 */ disableBookmark?: boolean; /** * Hide the download icon in the overflow menu. * Uses an undocumented Chromium intent extra — may stop working on future Chrome updates. * **Android only** — ignored on iOS. * @default false * @since 8.2.0 */ disableDownload?: boolean; } ``` ### `ClearCookieOptions` [Section titled “ClearCookieOptions”](#clearcookieoptions) ```typescript export interface ClearCookieOptions { /** * Target webview id. * When omitted, applies to all open webviews. */ id?: string; url: string; } ``` ### `GetCookieOptions` [Section titled “GetCookieOptions”](#getcookieoptions) ```typescript export interface GetCookieOptions { url: string; includeHttpOnly?: boolean; } ``` ### `CloseWebviewOptions` [Section titled “CloseWebviewOptions”](#closewebviewoptions) ```typescript export interface CloseWebviewOptions { /** * Target webview id to close. If omitted, closes the active webview. */ id?: string; /** * Whether the webview closing is animated or not, ios only * @default true */ isAnimated?: boolean; } ``` ### `OpenWebViewOptions` [Section titled “OpenWebViewOptions”](#openwebviewoptions) ````typescript export interface OpenWebViewOptions { /** * Target URL to load. * @since 0.1.0 * @example "https://capgo.app" */ url: string; /** * Headers to send with the request. * @since 0.1.0 * @example * headers: { * "Custom-Header": "test-value", * "Authorization": "Bearer test-token" * } * Test URL: https://www.whatismybrowser.com/detect/what-http-headers-is-my-browser-sending/ */ headers?: Headers; /** * Credentials to send with the request and all subsequent requests for the same host. * @since 6.1.0 * @example * credentials: { * username: "test-user", * password: "test-pass" * } * Test URL: https://www.whatismybrowser.com/detect/what-http-headers-is-my-browser-sending/ */ credentials?: Credentials; /** * HTTP method to use for the initial request. * * **Optional parameter - defaults to GET if not specified.** * Existing code that doesn't provide this parameter will continue to work unchanged with standard GET requests. * * When specified with 'POST', 'PUT', or 'PATCH' methods that support a body, * you can also provide a `body` parameter with the request payload. * * **Platform Notes:** * - iOS: Full support for all HTTP methods with headers * - Android: Custom headers may not be sent with POST/PUT/PATCH requests due to WebView limitations * * @since 8.2.0 * @default "GET" * @example * method: "POST", * body: JSON.stringify({ token: "auth-token", data: "value" }), * headers: { "Content-Type": "application/json" } */ method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS' | string; /** * HTTP body to send with the request when using POST, PUT, or other methods that support a body. * Should be a string (use JSON.stringify for JSON data). * * **Optional parameter - only used when `method` is specified and supports a request body.** * Omitting this parameter (or using GET method) results in standard behavior without a request body. * * @since 8.2.0 * @example * method: "POST", * body: JSON.stringify({ username: "user", password: "pass" }), * headers: { "Content-Type": "application/json" } */ body?: string; /** * materialPicker: if true, uses Material Design theme for date and time pickers on Android. * This improves the appearance of HTML date inputs to use modern Material Design UI instead of the old style pickers. * @since 7.4.1 * @default false * @example * materialPicker: true * Test URL: https://show-picker.glitch.me/demo.html */ materialPicker?: boolean; /** * JavaScript Interface: * The webview automatically injects a JavaScript interface providing: * - `window.mobileApp.close()`: Closes the webview from JavaScript * - `window.mobileApp.postMessage(obj)`: Sends a message to the app (listen via "messageFromWebview" event) * - `window.mobileApp.hide()` / `window.mobileApp.show()` when allowWebViewJsVisibilityControl is true in CapacitorConfig * - `window.mobileApp.takeScreenshot()` when `allowScreenshotsFromWebPage` is true * * @example * // In your webpage loaded in the webview: * document.getElementById("closeBtn").addEventListener("click", () => { * window.mobileApp.close(); * }); * * // Send data to the app * window.mobileApp.postMessage({ action: "login", data: { user: "test" }}); * * @since 6.10.0 */ jsInterface?: never; // This property doesn't exist, it's just for documentation /** * Allows page JavaScript to call `window.mobileApp.takeScreenshot()`. * Disabled by default so only the host app can trigger native screenshots through the plugin API. * * @default false * @since 8.4.0 */ allowScreenshotsFromWebPage?: boolean; /** * Emits `consoleMessage` events for JavaScript `console.*` output coming from the managed page. * Useful when the webview stays hidden and you still need page-level diagnostics. * * @default false * @since 8.6.0 */ captureConsoleLogs?: boolean; /** * Automatically handles downloads triggered inside the webview without requiring a custom JavaScript bridge. * * When enabled: * - Standard attachment responses are written to a temporary file. * - `blob:` downloads are also captured when the platform supports them. * - Previewable files reopen inside the in-app browser when possible. * - Other files are handed off to the native preview or viewer flow. * - `downloadCompleted` and `downloadFailed` events notify the host app about the saved file. * * @default false * @since 8.6.0 */ handleDownloads?: boolean; /** * Share options for the webview. When provided, shows a disclaimer dialog before sharing content. * This is useful for: * - Warning users about sharing sensitive information * - Getting user consent before sharing * - Explaining what will be shared * - Complying with privacy regulations * * Note: shareSubject is required when using shareDisclaimer * @since 0.1.0 * @example * shareDisclaimer: { * title: "Disclaimer", * message: "This is a test disclaimer", * confirmBtn: "Accept", * cancelBtn: "Decline" * } * Test URL: https://capgo.app */ shareDisclaimer?: DisclaimerOptions; /** * Toolbar type determines the appearance and behavior of the browser's toolbar * - "activity": Shows a simple toolbar with just a close button and share button * - "navigation": Shows a full navigation toolbar with back/forward buttons * - "blank": Shows no toolbar * - "": Default toolbar with close button * @since 0.1.0 * @default ToolBarType.DEFAULT * @example * toolbarType: ToolBarType.ACTIVITY, * title: "Activity Toolbar Test" * Test URL: https://capgo.app */ toolbarType?: ToolBarType; /** * Subject text for sharing. Required when using shareDisclaimer. * This text will be used as the subject line when sharing content. * @since 0.1.0 * @example "Share this page" */ shareSubject?: string; /** * Title of the browser * @since 0.1.0 * @default "New Window" * @example "Camera Test" */ title?: string; /** * Background color of the browser * @since 0.1.0 * @default BackgroundColor.BLACK */ backgroundColor?: BackgroundColor; /** * If true, enables native navigation gestures within the webview. * - Android: Native back button navigates within webview history * - iOS: Enables swipe left/right gestures for back/forward navigation * @default false (Android), true (iOS - enabled by default) * @example * activeNativeNavigationForWebview: true, * disableGoBackOnNativeApplication: true * Test URL: https://capgo.app */ activeNativeNavigationForWebview?: boolean; /** * Disable the possibility to go back on native application, * useful to force user to stay on the webview, Android only * @default false * @example * disableGoBackOnNativeApplication: true * Test URL: https://capgo.app */ disableGoBackOnNativeApplication?: boolean; /** * Open url in a new window fullscreen * isPresentAfterPageLoad: if true, the browser will be presented after the page is loaded, if false, the browser will be presented immediately. * Promise timing: on Android, `openWebView()` resolves with the webview id when the webview is ready to be controlled * (immediately for hidden/immediate presentation, after the first page load when `isPresentAfterPageLoad` is `true`). * On iOS, the promise resolves with the id as soon as the native webview is created, even if presentation is deferred. * @since 0.1.0 * @default false * @example * isPresentAfterPageLoad: true, * preShowScript: "await import('https://unpkg.com/darkreader@4.9.89/darkreader.js');\nDarkReader.enable({ brightness: 100, contrast: 90, sepia: 10 });" * Test URL: https://capgo.app */ isPresentAfterPageLoad?: boolean; /** * Whether the website in the webview is inspectable or not, ios only * @default false */ isInspectable?: boolean; /** * Whether the webview opening is animated or not, ios only * @default true */ isAnimated?: boolean; /** * Shows a reload button that reloads the web page * @since 1.0.15 * @default false * @example * showReloadButton: true * Test URL: https://capgo.app */ showReloadButton?: boolean; /** * CloseModal: if true a confirm will be displayed when user clicks on close button, if false the browser will be closed immediately. * @since 1.1.0 * @default false * @example * closeModal: true, * closeModalTitle: "Close Window", * closeModalDescription: "Are you sure you want to close?", * closeModalOk: "Yes, close", * closeModalCancel: "No, stay" * Test URL: https://capgo.app */ closeModal?: boolean; /** * CloseModalTitle: title of the confirm when user clicks on close button * @since 1.1.0 * @default "Close" */ closeModalTitle?: string; /** * CloseModalDescription: description of the confirm when user clicks on close button * @since 1.1.0 * @default "Are you sure you want to close this window?" */ closeModalDescription?: string; /** * CloseModalOk: text of the confirm button when user clicks on close button * @since 1.1.0 * @default "Close" */ closeModalOk?: string; /** * CloseModalCancel: text of the cancel button when user clicks on close button * @since 1.1.0 * @default "Cancel" */ closeModalCancel?: string; /** * closeModalURLPattern: a regex pattern to match against the current URL when the close button is pressed. * When provided along with closeModal: true, the close confirmation modal is only shown if the current URL matches this pattern. * If the current URL does not match, the browser closes immediately without showing the modal. * Requires closeModal to be true. * @since 7.2.0 * @example * closeModal: true, * closeModalURLPattern: ".*checkout.*" */ closeModalURLPattern?: string; /** * visibleTitle: if true the website title would be shown else shown empty * @since 1.2.5 * @default true */ visibleTitle?: boolean; /** * toolbarColor: color of the toolbar in hex format * @since 1.2.5 * @default "#ffffff" * @example * toolbarColor: "#FF5733" * Test URL: https://capgo.app */ toolbarColor?: string; /** * toolbarTextColor: color of the buttons and title in the toolbar in hex format * When set, it overrides the automatic light/dark mode detection for text color * @since 6.10.0 * @default calculated based on toolbarColor brightness * @example * toolbarTextColor: "#FFFFFF" * Test URL: https://capgo.app */ toolbarTextColor?: string; /** * showArrow: if true an arrow would be shown instead of cross for closing the window * @since 1.2.5 * @default false * @example * showArrow: true * Test URL: https://capgo.app */ showArrow?: boolean; /** * ignoreUntrustedSSLError: if true, the webview will ignore untrusted SSL errors allowing the user to view the website. * @since 6.1.0 * @default false */ ignoreUntrustedSSLError?: boolean; /** * preShowScript: if isPresentAfterPageLoad is true and this variable is set the plugin will inject a script before showing the browser. * This script will be run in an async context. The plugin will wait for the script to finish (max 10 seconds) * @since 6.6.0 * @example * preShowScript: "await import('https://unpkg.com/darkreader@4.9.89/darkreader.js');\nDarkReader.enable({ brightness: 100, contrast: 90, sepia: 10 });" * Test URL: https://capgo.app */ preShowScript?: string; /** * preShowScriptInjectionTime: controls when the preShowScript is injected. * - "documentStart": injects before any page JavaScript runs (good for polyfills like Firebase) * - "pageLoad": injects after page load (default, original behavior) * @since 7.26.0 * @default "pageLoad" * @example * preShowScriptInjectionTime: "documentStart" */ preShowScriptInjectionTime?: 'documentStart' | 'pageLoad'; /** * Proxy interception mode. * * - `true`: legacy blanket mode, delegates all HTTP/HTTPS requests to JavaScript. * - `string`: Android-only regex mode kept for backward compatibility. * * Prefer `outboundProxyRules` and `inboundProxyRules` for native-first matching. * * @since 6.9.0 */ proxyRequests?: boolean | string; /** * Native-first outbound proxy rules. * * @since 8.6.0 */ outboundProxyRules?: NativeProxyRule[]; /** * Native-first inbound proxy rules. * * @since 8.6.0 */ inboundProxyRules?: NativeProxyRule[]; /** * buttonNearDone allows for a creation of a custom button near the done/close button. * The button is only shown when toolbarType is not "activity", "navigation", or "blank". * * For Android: * - iconType must be "asset" * - icon path should be in the public folder (e.g. "monkey.svg") * - width and height are optional, defaults to 48dp * - button is positioned at the end of toolbar with 8dp margin * * For iOS: * - iconType can be "sf-symbol" or "asset" * - for sf-symbol, icon should be the symbol name * - for asset, icon should be the asset name * @since 6.7.0 * @example * buttonNearDone: { * ios: { * iconType: "sf-symbol", * icon: "star.fill" * }, * android: { * iconType: "asset", * icon: "public/monkey.svg", * width: 24, * height: 24 * } * } * Test URL: https://capgo.app */ buttonNearDone?: { ios: { iconType: 'sf-symbol' | 'asset'; icon: string; }; android: { iconType: 'asset' | 'vector'; icon: string; width?: number; height?: number; }; }; /** * Shows a native screenshot button near the done/close button. * The button is hidden by default and captures the current viewport when tapped. * This option uses the same toolbar slot as `buttonNearDone` and is therefore incompatible with it. * The button is only shown when toolbarType is not "activity", "navigation", or "blank". * * @default false * @since 8.4.0 */ showScreenshotButton?: boolean; /** * textZoom: sets the text zoom of the page in percent. * Allows users to increase or decrease the text size for better readability. * @since 7.6.0 * @default 100 * @example * textZoom: 120 * Test URL: https://capgo.app */ textZoom?: number; /** * enableZoom: enables pinch-to-zoom gestures in the Android WebView. * When true, built-in zoom controls are enabled and the zoom buttons are hidden. * **Android only** — ignored on iOS where zoom is enabled by default. * @since 8.5.0 * @default false * @example * enableZoom: true */ enableZoom?: boolean; /** * preventDeeplink: if true, the deeplink will not be opened, if false the deeplink will be opened when clicked on the link. on IOS each schema need to be added to info.plist file under LSApplicationQueriesSchemes when false to make it work. * @since 0.1.0 * @default false * @example * preventDeeplink: true * Test URL: https://aasa-tester.capgo.app/ */ preventDeeplink?: boolean; /** * When true, HTTP and HTTPS links opened from `target="_blank"` anchors stay in the current webview instead of spawning a popup or opening in the system browser. * By default, blank-target HTTP(S) links stay inside the plugin as managed popups that share cookies with the opener; enabling this option keeps everything in the same tab. * Custom schemes such as `tel:` and `mailto:` and authorized app links still prefer their native handlers unless `preventDeeplink` is enabled. * * @since 8.5.6 * @default false * @example * openBlankTargetInWebView: true */ openBlankTargetInWebView?: boolean; /** * List of base URLs whose hosts are treated as authorized App Links (Android) and Universal Links (iOS). * * - On both platforms, only HTTPS links whose host matches any entry in this list * will attempt to open via the corresponding native application. * - If the app is not installed or the system cannot handle the link, the URL * will continue loading inside the in-app browser. * - Matching is host-based (case-insensitive), ignoring the "www." prefix. * - When `preventDeeplink` is enabled, all external handling is blocked regardless of this list. * * @example * ```ts * ["https://example.com", "https://subdomain.app.io"] * ``` * * @since 7.12.0 * @default [] */ authorizedAppLinks?: string[]; /** * If true, the webView will not take the full height and will have a 20px margin at the bottom. * This creates a safe margin area outside the browser view. * @since 7.13.0 * @default false * @example * enabledSafeBottomMargin: true */ enabledSafeBottomMargin?: boolean; /** * If false, the webView will extend behind the status bar for true full-screen immersive content. * When true (default), respects the safe area at the top of the screen. * Works independently of toolbarType - use for full-screen video players, games, or immersive web apps. * @since 8.2.0 * @default true * @example * enabledSafeTopMargin: false // Full screen, extends behind status bar */ enabledSafeTopMargin?: boolean; /** * When true, applies the system status bar inset as the WebView top margin on Android. * Keeps the legacy 0px margin by default for apps that handle padding themselves. * @default false * @example * useTopInset: true */ useTopInset?: boolean; /** * enableGooglePaySupport: if true, enables support for Google Pay popups and Payment Request API. * This fixes OR_BIBED_15 errors by allowing popup windows and configuring Cross-Origin-Opener-Policy. * Only enable this if you need Google Pay functionality as it allows popup windows. * * When enabled: * - Allows popup windows for Google Pay authentication * - Sets proper CORS headers for Payment Request API * - Enables multiple window support in WebView * - Configures secure context for payment processing * * @since 7.13.0 * @default false * @example * enableGooglePaySupport: true * Test URL: https://developers.google.com/pay/api/web/guides/tutorial */ enableGooglePaySupport?: boolean; /** * Opens popup windows created by the page in hidden mode. * Hidden popup windows can still be controlled with `executeScript`, `postMessage`, `show`, and `close`. * Listen to `popupWindowOpened` to capture the popup id, then call `show({ id })` only if you want to reveal it. * * @default false * @since 8.6.0 * @example * hiddenPopupWindow: true */ hiddenPopupWindow?: boolean; /** * blockedHosts: List of host patterns that should be blocked from loading in the InAppBrowser's internal navigations. * Any request inside WebView to a URL with a host matching any of these patterns will be blocked. * Supports wildcard patterns like: * - "*.example.com" to block all subdomains * - "www.example.*" to block wildcard domain extensions * * @since 7.17.0 * @default [] * @example * blockedHosts: ["*.tracking.com", "ads.example.com"] */ blockedHosts?: string[]; /** * Width of the webview in pixels. * If not set, webview will be fullscreen width. * @default undefined (fullscreen) * @example * width: 400 */ width?: number; /** * Height of the webview in pixels. * If not set, webview will be fullscreen height. * @default undefined (fullscreen) * @example * height: 600 */ height?: number; /** * X position of the webview in pixels from the left edge. * Only effective when width is set. * @default 0 * @example * x: 50 */ x?: number; /** * Y position of the webview in pixels from the top edge. * Only effective when height is set. * @default 0 * @example * y: 100 */ y?: number; /** * Disables the bounce (overscroll) effect on iOS WebView. * When enabled, prevents the rubber band scrolling effect when users scroll beyond content boundaries. * This is useful for: * - Creating a more native, app-like experience * - Preventing accidental overscroll states * - Avoiding issues when keyboard opens/closes * * Note: This option only affects iOS. Android does not have this bounce effect by default. * * @since 8.0.2 * @default false * @example * disableOverscroll: true */ disableOverscroll?: boolean; /** * Opens the webview in hidden mode (not visible to user but fully functional). * When hidden, the webview loads and executes JavaScript but is not displayed. * All control methods (executeScript, postMessage, setUrl, etc.) work while hidden. * Use close() to clean up the hidden webview when done. * * @since 8.0.7 * @default false * @example * hidden: true */ hidden?: boolean; /** * Controls how a hidden webview reports its visibility and size. * - AWARE: webview is aware it's hidden (dimensions may be zero). * - FAKE_VISIBLE: webview is hidden but reports fullscreen dimensions (uses alpha=0 to remain invisible). * * @default InvisibilityMode.AWARE * @example * invisibilityMode: InvisibilityMode.FAKE_VISIBLE */ invisibilityMode?: InvisibilityMode; } ```` ### `ScreenshotResult` [Section titled “ScreenshotResult”](#screenshotresult) ```typescript export interface ScreenshotResult { /** * Image format used for the screenshot. */ format: '.png'; /** * MIME type of the generated screenshot. */ mimeType: 'image/.png'; /** * Base64-encoded screenshot payload without the data URL prefix. */ base64: string; /** * Data URL for direct use in HTML img tags or uploads. */ dataUrl: string; /** * Screenshot width in pixels. */ width: number; /** * Screenshot height in pixels. */ height: number; } ``` ### `UrlChangeListener` [Section titled “UrlChangeListener”](#urlchangelistener) ```typescript export type UrlChangeListener = (state: UrlEvent) => void; ``` ### `ButtonNearListener` [Section titled “ButtonNearListener”](#buttonnearlistener) ```typescript export type ButtonNearListener = (state: object) => void; ``` ### `ConfirmBtnListener` [Section titled “ConfirmBtnListener”](#confirmbtnlistener) ```typescript export type ConfirmBtnListener = (state: BtnEvent) => void; ``` ### `DownloadCompletedEvent` [Section titled “DownloadCompletedEvent”](#downloadcompletedevent) Event emitted after a managed download is saved locally. ```typescript export interface DownloadCompletedEvent { /** * Source webview instance id. */ id?: string; /** * Original URL that triggered the download when available. */ sourceUrl?: string; /** * Saved filename. */ fileName: string; /** * Resolved MIME type when available. */ mimeType?: string; /** * Absolute native filesystem path to the saved file. */ path: string; /** * `file://` URL pointing at the saved file. */ localUrl: string; /** * How native handled the downloaded file after saving it. */ handledBy: DownloadHandledBy; } ``` ### `DownloadFailedEvent` [Section titled “DownloadFailedEvent”](#downloadfailedevent) Event emitted when managed download handling fails. ```typescript export interface DownloadFailedEvent { /** * Source webview instance id. */ id?: string; /** * Original URL that triggered the download when available. */ sourceUrl?: string; /** * Intended filename when known. */ fileName?: string; /** * Resolved MIME type when available. */ mimeType?: string; /** * Native error message. */ error: string; } ``` ### `PopupWindowEvent` [Section titled “PopupWindowEvent”](#popupwindowevent) Event emitted when a web page opens a popup/new window. ```typescript export interface PopupWindowEvent { /** * Popup webview instance id. */ id: string; /** * Parent webview instance id. */ parentId?: string; /** * Requested popup URL when available. */ url?: string; /** * Whether the popup was presented immediately. */ visible: boolean; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-incoming-call-kit > Capacitor API for presenting a native incoming-call surface. ## Overview [Section titled “Overview”](#overview) Capacitor API for presenting a native incoming-call surface. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `showIncomingCall` - Displays the native incoming call UI. * `endCall` - Ends a specific tracked call. * `endAllCalls` - Ends every tracked call. * `getActiveCalls` - Returns the currently tracked calls. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ----------------------------------- | ------------------------------------------------------------------------------- | | `showIncomingCall` | Displays the native incoming call UI. | | `endCall` | Ends a specific tracked call. | | `endAllCalls` | Ends every tracked call. | | `getActiveCalls` | Returns the currently tracked calls. | | `checkPermissions` | Returns the current permission state for notifications and full-screen intents. | | `requestPermissions` | Requests the notification permission when the platform supports it. | | `requestFullScreenIntentPermission` | Opens the Android 14+ full-screen intent settings page when available. | | `getPluginVersion` | Returns the native implementation version marker. | | `addListener` | Fired after the call has been handed to the native platform UI. | | `addListener` | Fired when the user accepts the call from native UI. | | `addListener` | Fired when the user declines the call from native UI. | | `addListener` | Fired when a call ends through the API or a platform action. | | `addListener` | Fired when an unanswered call reaches its configured timeout. | | `removeAllListeners` | Removes every native listener registered by the plugin. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-incoming-call-kit](https://github.com/Cap-go/capacitor-incoming-call-kit/). # Android > Configure notifications, full-screen intents, and Android-specific incoming-call behavior. ## How Android behavior works [Section titled “How Android behavior works”](#how-android-behavior-works) On Android, the plugin posts a high-priority incoming-call notification and can raise a full-screen activity when the platform and user settings allow it. The plugin manifest already includes: ```xml <uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" /> ``` After installation, `cap sync` is enough to merge that configuration into your host app. ## Runtime permissions [Section titled “Runtime permissions”](#runtime-permissions) Call these methods during onboarding or before you rely on incoming-call presentation: ```ts import { IncomingCallKit } from '@capgo/capacitor-incoming-call-kit'; await IncomingCallKit.requestPermissions(); await IncomingCallKit.requestFullScreenIntentPermission(); ``` * `requestPermissions()` requests notification permission on Android 13 and later. * `requestFullScreenIntentPermission()` opens the Android 14 and later settings page for full-screen intents when needed. ## Basic example [Section titled “Basic example”](#basic-example) ```ts import { IncomingCallKit } from '@capgo/capacitor-incoming-call-kit'; await IncomingCallKit.showIncomingCall({ callId: 'call-42', callerName: 'Ada Lovelace', appName: 'Capgo Phone', timeoutMs: 45_000, android: { channelId: 'calls', channelName: 'Incoming Calls', showFullScreen: true, isHighPriority: true, accentColor: '#0F766E', }, }); ``` ## Android-specific options [Section titled “Android-specific options”](#android-specific-options) * `channelId`: identifier for the notification channel * `channelName`: user-visible channel name * `showFullScreen`: request the full-screen activity * `isHighPriority`: keep the notification disruptive enough for ringing flows * `accentColor`: tint compatible notification surfaces * `ringtoneUri`: point at a custom Android ringtone resource or URI ## Behavior notes [Section titled “Behavior notes”](#behavior-notes) * Full-screen presentation is best-effort. If the device or user settings block it, Android still shows the incoming-call notification. * Timeout handling is best-effort. The plugin tracks `timeoutMs` and emits `callTimedOut`, but your backend should still reconcile missed calls on its side. * Accept, decline, and end actions are emitted back through Capacitor listeners so your app can join or clean up the real call session. ## Recommended production model [Section titled “Recommended production model”](#recommended-production-model) Use Android push or your calling SDK for transport, then let this plugin handle the last mile of native ringing UI. Keep these responsibilities outside the plugin: * FCM registration and token management * Media session lifecycle * Backend call state * Retry and missed-call business logic # Getting Started > Install and wire incoming call presentation in Capacitor with a transport-agnostic API. 1. **Install the package** ```sh bun add @capgo/capacitor-incoming-call-kit ``` 2. **Sync native projects** ```sh bunx cap sync ``` 3. **Choose your ring source** Decide whether the incoming-call event comes from your backend, an SDK such as Twilio or Stream, or a native push path such as FCM or PushKit. ## How the integration fits together [Section titled “How the integration fits together”](#how-the-integration-fits-together) This plugin only owns native incoming-call presentation. Your app still owns transport, authentication, and the actual media session. The common production pattern is: 1. Your backend or calling SDK emits a ring event. 2. Your app calls `showIncomingCall()`. 3. The plugin presents native incoming-call UI. 4. `callAccepted` tells your app to join the actual room or VoIP session. 5. `callDeclined`, `callEnded`, or `callTimedOut` tells your app to clean up remote state. ## Minimal integration [Section titled “Minimal integration”](#minimal-integration) ```ts import { IncomingCallKit } from '@capgo/capacitor-incoming-call-kit'; await IncomingCallKit.requestPermissions(); await IncomingCallKit.requestFullScreenIntentPermission(); await IncomingCallKit.addListener('callAccepted', async ({ call }) => { console.log('Accepted', call.callId, call.extra); // Start or join your real call session here. }); await IncomingCallKit.addListener('callDeclined', ({ call }) => { console.log('Declined', call.callId); // Tell your backend or SDK that the user declined. }); await IncomingCallKit.addListener('callTimedOut', ({ call }) => { console.log('Timed out', call.callId); // Clear ringing state in your backend or SDK. }); await IncomingCallKit.showIncomingCall({ callId: 'call-42', callerName: 'Ada Lovelace', handle: '+39 555 010 020', appName: 'Capgo Phone', hasVideo: true, timeoutMs: 45_000, extra: { roomId: 'room-42', callerUserId: 'user_ada', }, android: { channelId: 'calls', channelName: 'Incoming Calls', showFullScreen: true, }, ios: { handleType: 'phoneNumber', }, }); ``` ## Important options [Section titled “Important options”](#important-options) * `callId`: stable identifier reused later with `endCall()` * `timeoutMs`: best-effort unanswered timeout * `extra`: arbitrary JSON echoed back in listener payloads * `android.channelId` and `android.channelName`: Android notification channel tuning * `android.showFullScreen`: requests the Android full-screen incoming-call activity * `ios.handleType`: choose `generic`, `phoneNumber`, or `emailAddress` for CallKit ## Managing active calls [Section titled “Managing active calls”](#managing-active-calls) ```ts const { calls } = await IncomingCallKit.getActiveCalls(); await IncomingCallKit.endCall({ callId: 'call-42', reason: 'remote-ended', }); await IncomingCallKit.endAllCalls({ reason: 'session-reset', }); ``` ## Event model [Section titled “Event model”](#event-model) * `incomingCallDisplayed`: native UI was shown successfully * `callAccepted`: user accepted from the native UI * `callDeclined`: user declined before joining * `callEnded`: your app or the platform ended the tracked call * `callTimedOut`: the call stayed unanswered until `timeoutMs` Each event carries the normalized `call` payload and your original `extra` object. ## Platform notes [Section titled “Platform notes”](#platform-notes) * Read the [iOS guide](/docs/plugins/incoming-call-kit/ios/) before wiring CallKit into a PushKit or APNs flow. * Read the [Android guide](/docs/plugins/incoming-call-kit/android/) before relying on full-screen intents on Android 14 and later. * Web is not supported. # iOS > Configure CallKit behavior and understand production limits on iOS. ## How iOS behavior works [Section titled “How iOS behavior works”](#how-ios-behavior-works) On iOS, the plugin reports the incoming call to CallKit. That gives you the system incoming-call sheet and standardized call actions without building your own native incoming-call UI. `requestPermissions()` resolves immediately on iOS because CallKit itself does not require a runtime permission dialog. ## Basic example [Section titled “Basic example”](#basic-example) ```ts import { IncomingCallKit } from '@capgo/capacitor-incoming-call-kit'; await IncomingCallKit.showIncomingCall({ callId: 'call-42', callerName: 'Ada Lovelace', handle: '+1 555 010 020', ios: { handleType: 'phoneNumber', supportsHolding: true, supportsDTMF: false, }, }); ``` ## Handle types [Section titled “Handle types”](#handle-types) Use `ios.handleType` to control how CallKit formats the handle: * `generic` for app-specific identifiers * `phoneNumber` for real phone numbers * `emailAddress` for email-based identities ## Background incoming calls [Section titled “Background incoming calls”](#background-incoming-calls) This plugin does not register PushKit or APNs for you. For true background or terminated-state ringing on iOS, your host app still needs the native Apple push setup that matches your transport strategy: 1. Enable Push Notifications when your transport uses Apple push delivery. 2. Enable the Voice over IP background mode when your app uses a VoIP push flow. 3. Deliver the incoming-call event to your app and invoke this plugin as soon as the Capacitor bridge is available. If your ring event exists only in JavaScript, you will get the best experience while the app is already running in the foreground. ## Microphone and camera permissions [Section titled “Microphone and camera permissions”](#microphone-and-camera-permissions) CallKit does not replace your media SDK. If the real call session uses microphone or camera access, those usage descriptions still belong in your app: ```xml <key>NSMicrophoneUsageDescription</key> <string>This app uses the microphone for calls.</string> <key>NSCameraUsageDescription</key> <string>This app uses the camera for video calls.</string> ``` Add only the keys your real calling flow needs. ## Keep these responsibilities in your app layer [Section titled “Keep these responsibilities in your app layer”](#keep-these-responsibilities-in-your-app-layer) * PushKit and APNs registration * Authentication and token refresh * Joining the real room or VoIP session after `callAccepted` * Ending or reconciling remote call state when the plugin emits `callDeclined`, `callEnded`, or `callTimedOut` # @capgo/capacitor-install-referrer > Read Android Play install referrer data and iOS Apple AdServices attribution tokens from Capacitor. ## Overview [Section titled “Overview”](#overview) `@capgo/capacitor-install-referrer` exposes install attribution signals through one Capacitor API. On Android, it reads Google Play Install Referrer details: the raw referrer string, click timestamp, install timestamp, and instant app flag. On iOS, it returns an Apple AdServices attribution token and can optionally call Apple’s AdServices attribution endpoint for Apple Search Ads attribution data. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `getReferrer` - Return native install attribution details for the current platform. * `GetReferrer` - Deprecated compatibility alias for apps migrating from `cap-play-install-referrer`. * `getPluginVersion` - Return the native plugin implementation version marker. * Optional iOS Apple attribution lookup with retry support for delayed AdServices responses. ## Platform Support [Section titled “Platform Support”](#platform-support) | Platform | Support | | -------- | ------------------------------------------------------------------------- | | Android | Google Play Install Referrer API | | iOS | Apple AdServices attribution token and optional Apple attribution payload | | Web | Unsupported stub | ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ----------------------- | ------------------------------------------------------ | | `getReferrer(options?)` | Return install attribution details for Android or iOS. | | `GetReferrer(options?)` | Deprecated compatibility alias for `getReferrer`. | | `getPluginVersion()` | Return the native plugin version marker. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-install-referrer](https://github.com/Cap-go/capacitor-install-referrer/). # Android Referrer > Android behavior for @capgo/capacitor-install-referrer. ## Google Play Install Referrer [Section titled “Google Play Install Referrer”](#google-play-install-referrer) On Android, `getReferrer()` connects to the Google Play Install Referrer service and returns data from the Play Store install record. ```typescript const result = await InstallReferrer.getReferrer(); console.log(result.referrer); console.log(result.clickTimestampSeconds); console.log(result.installBeginTimestampSeconds); console.log(result.googlePlayInstantParam); ``` ## Returned Fields [Section titled “Returned Fields”](#returned-fields) | Field | Description | | ------------------------------ | ------------------------------------------------------- | | `platform` | Always `android`. | | `referrer` | Raw Play install referrer string. | | `clickTimestampSeconds` | Client-side referrer click timestamp in seconds. | | `installBeginTimestampSeconds` | Client-side install begin timestamp in seconds. | | `googlePlayInstantParam` | Whether the user launched the app’s instant experience. | ## Requirements [Section titled “Requirements”](#requirements) * The app must be installed from Google Play for real install referrer data. * The device must have a Play Store version that supports the Install Referrer service. * No Android runtime permission is required. ## Error Cases [Section titled “Error Cases”](#error-cases) The plugin rejects when the Play Store service is unavailable, unsupported, disconnected before returning a result, or returns an unexpected response. # Getting Started > Install @capgo/capacitor-install-referrer and read install attribution data in a Capacitor app. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-install-referrer bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { InstallReferrer } from '@capgo/capacitor-install-referrer'; ``` ## Read Attribution Details [Section titled “Read Attribution Details”](#read-attribution-details) ```typescript const result = await InstallReferrer.getReferrer(); if (result.platform === 'android') { console.log('Install referrer:', result.referrer); console.log('Click timestamp:', result.clickTimestampSeconds); console.log('Install timestamp:', result.installBeginTimestampSeconds); } if (result.platform === 'ios') { console.log('AdServices token:', result.attributionToken); } ``` ## Fetch Apple Attribution On iOS [Section titled “Fetch Apple Attribution On iOS”](#fetch-apple-attribution-on-ios) If you want native code to call Apple’s attribution endpoint, pass `fetchAppleAttribution`. ```typescript const result = await InstallReferrer.getReferrer({ fetchAppleAttribution: true, appleAttributionRetryCount: 3, appleAttributionRetryDelayMs: 5000, }); // result.appleAttribution is the parsed Apple attribution response. // See the iOS attribution page for the Apple-provided payload fields. console.log(result.appleAttribution); ``` Apple can return `404` while attribution data is still being prepared for a valid token. The retry options control how often the native plugin retries before rejecting. See [iOS attribution](/docs/plugins/install-referrer/ios/) for platform details. ## Compatibility Alias [Section titled “Compatibility Alias”](#compatibility-alias) `GetReferrer()` is available for apps migrating from `cap-play-install-referrer`. ```typescript const result = await InstallReferrer.GetReferrer(); ``` New code should use `getReferrer()`. # iOS Attribution > iOS behavior for @capgo/capacitor-install-referrer with Apple AdServices. ## Apple AdServices [Section titled “Apple AdServices”](#apple-adservices) Apple does not provide a generic App Store install referrer equivalent to Google Play Install Referrer. On iOS, this plugin uses Apple AdServices attribution. By default, `getReferrer()` returns an AdServices attribution token that you can send to your backend or mobile measurement partner. ```typescript const result = await InstallReferrer.getReferrer(); console.log(result.attributionToken); ``` ## Native Apple Attribution Lookup [Section titled “Native Apple Attribution Lookup”](#native-apple-attribution-lookup) The plugin can also send the token to Apple’s AdServices endpoint from native code. ```typescript const result = await InstallReferrer.getReferrer({ fetchAppleAttribution: true, }); console.log(result.appleAttribution); ``` Use this mode when the app itself should receive Apple’s attribution payload. Keep `fetchAppleAttribution` false when your backend or attribution provider should exchange the token. ## Returned Fields [Section titled “Returned Fields”](#returned-fields) | Field | Description | | ------------------ | ------------------------------------------------------------------------ | | `platform` | Always `ios`. | | `attributionToken` | Apple AdServices attribution token. | | `appleAttribution` | Optional Apple attribution payload when `fetchAppleAttribution` is true. | ## Requirements [Section titled “Requirements”](#requirements) * Apple AdServices attribution tokens are available on iOS 14.3 and later. * The attribution payload covers Apple Search Ads attribution, not arbitrary App Store referrer URLs. * No App Tracking Transparency prompt is required just to request the AdServices attribution token. # @capgo/capacitor-intent-launcher > Capacitor Intent Launcher Plugin for launching Android intents and opening system settings on both Android and iOS. ## Overview [Section titled “Overview”](#overview) Capacitor Intent Launcher Plugin for launching Android intents and opening system settings on both Android and iOS. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `startActivityAsync` - Starts an Android activity for the given action. * `openIOSSettings` - Opens iOS settings screen. * `openApplication` - Opens an application by its package name. * `getApplicationIconAsync` - Gets the application icon as a base64-encoded PNG string. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------------- | --------------------------------------------------------- | | `startActivityAsync` | Starts an Android activity for the given action. | | `openIOSSettings` | Opens iOS settings screen. | | `openApplication` | Opens an application by its package name. | | `getApplicationIconAsync` | Gets the application icon as a base64-encoded PNG string. | | `getPluginVersion` | Get the native Capacitor plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-intent-launcher](https://github.com/Cap-go/capacitor-intent-launcher/). # Getting Started > Install @capgo/capacitor-intent-launcher and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-intent-launcher bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { IntentLauncher } from '@capgo/capacitor-intent-launcher'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `startActivityAsync` [Section titled “startActivityAsync”](#startactivityasync) Starts an Android activity for the given action. ```typescript import { IntentLauncher } from '@capgo/capacitor-intent-launcher'; // Open location settings const result = await IntentLauncher.startActivityAsync({ action: ActivityAction.LOCATION_SOURCE_SETTINGS }); // Open a specific app settings const result = await IntentLauncher.startActivityAsync({ action: ActivityAction.APPLICATION_DETAILS_SETTINGS, data: 'package:com.example.app' }); ``` ### `openIOSSettings` [Section titled “openIOSSettings”](#openiossettings) Opens iOS settings screen. Note: The only officially supported option by Apple is `App` which opens your app’s settings page. Other options may work but are not guaranteed and could break in future iOS versions or cause App Store rejection. Also note that the iOS Simulator will sometimes only open the Settings app, instead of the specified option. ```typescript import { IntentLauncher } from '@capgo/capacitor-intent-launcher'; // Open app settings (recommended - officially supported by Apple) await IntentLauncher.openIOSSettings({ option: IOSSettings.App }); // Open WiFi settings (may not work in all iOS versions) await IntentLauncher.openIOSSettings({ option: IOSSettings.WiFi }); ``` ### `openApplication` [Section titled “openApplication”](#openapplication) Opens an application by its package name. ```typescript import { IntentLauncher } from '@capgo/capacitor-intent-launcher'; // Open Gmail app await IntentLauncher.openApplication({ packageName: 'com.google.android.gm' }); ``` ### `getApplicationIconAsync` [Section titled “getApplicationIconAsync”](#getapplicationiconasync) Gets the application icon as a base64-encoded PNG string. ```typescript import { IntentLauncher } from '@capgo/capacitor-intent-launcher'; const { icon } = await IntentLauncher.getApplicationIconAsync({ packageName: 'com.google.android.gm' }); if (icon) { const img = document.createElement('img'); img.src = icon; } ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `IntentLauncherParams` [Section titled “IntentLauncherParams”](#intentlauncherparams) Options for starting an activity. ```typescript export interface IntentLauncherParams { /** * The action to perform. Use values from `ActivityAction` enum. * * @since 1.0.0 */ action: string; /** * Optional category to add to the intent. * * @since 1.0.0 */ category?: string; /** * Optional class name for the component to launch. * * @since 1.0.0 */ className?: string; /** * Optional URI data for the intent. Must be a valid URI. * * @since 1.0.0 */ data?: string; /** * Optional extra data to pass to the intent as key-value pairs. * * @since 1.0.0 */ extra?: Record<string, unknown>; /** * Optional intent flags as a bitmask. * * @since 1.0.0 */ flags?: number; /** * Optional package name for the component. * * @since 1.0.0 */ packageName?: string; /** * Optional MIME type for the intent data. * * @since 1.0.0 */ type?: string; } ``` ### `IntentLauncherResult` [Section titled “IntentLauncherResult”](#intentlauncherresult) Result from starting an activity. ```typescript export interface IntentLauncherResult { /** * The result code returned by the activity. * * @since 1.0.0 */ resultCode: ResultCode; /** * Optional data URI returned by the activity. * * @since 1.0.0 */ data?: string; /** * Optional extra data returned by the activity. * * @since 1.0.0 */ extra?: Record<string, unknown>; } ``` ### `IOSSettingsParams` [Section titled “IOSSettingsParams”](#iossettingsparams) Options for opening iOS settings. ```typescript export interface IOSSettingsParams { /** * The iOS settings screen to open. Use values from `IOSSettings` enum. * * @since 8.2.0 */ option: string; } ``` ### `IOSSettingsResult` [Section titled “IOSSettingsResult”](#iossettingsresult) Result from opening iOS settings. ```typescript export interface IOSSettingsResult { /** * Whether the settings screen was successfully opened. * * @since 8.2.0 */ success: boolean; } ``` ### `OpenApplicationOptions` [Section titled “OpenApplicationOptions”](#openapplicationoptions) Options for opening an application. ```typescript export interface OpenApplicationOptions { /** * The package name of the application to open. * * @since 1.0.0 */ packageName: string; } ``` ### `GetApplicationIconOptions` [Section titled “GetApplicationIconOptions”](#getapplicationiconoptions) Options for getting an application icon. ```typescript export interface GetApplicationIconOptions { /** * The package name of the application. * * @since 1.0.0 */ packageName: string; } ``` ### `GetApplicationIconResult` [Section titled “GetApplicationIconResult”](#getapplicationiconresult) Result from getting an application icon. ```typescript export interface GetApplicationIconResult { /** * The application icon as a base64-encoded PNG string prefixed with 'data:image/.png;base64,'. * Empty string if the icon is not available. * * @since 1.0.0 */ icon: string; } ``` ### `ResultCode` [Section titled “ResultCode”](#resultcode) Result codes returned by activities. ```typescript export enum ResultCode { /** * The activity completed successfully. */ Success = -1, /** * The activity was canceled by the user. */ Canceled = 0, /** * First custom user-defined result code. */ FirstUser = 1, } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-intercom > Intercom Capacitor plugin. ## Overview [Section titled “Overview”](#overview) Intercom Capacitor plugin. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `loadWithKeys` - Initialize Intercom with API keys at runtime. Use this if you prefer not to configure keys in capacitor.config. * `registerIdentifiedUser` - Register a known user with Intercom. At least one of userId or email must be provided. * `registerUnidentifiedUser` - Register an anonymous user with Intercom. * `updateUser` - Update user attributes in Intercom. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ---------------------------- | --------------------------------------------------------------------------------------------------------------- | | `loadWithKeys` | Initialize Intercom with API keys at runtime. Use this if you prefer not to configure keys in capacitor.config. | | `registerIdentifiedUser` | Register a known user with Intercom. At least one of userId or email must be provided. | | `registerUnidentifiedUser` | Register an anonymous user with Intercom. | | `updateUser` | Update user attributes in Intercom. | | `logout` | Log the user out of Intercom. | | `logEvent` | Log a custom event in Intercom. | | `displayMessenger` | Open the Intercom messenger. | | `displayMessageComposer` | Open the message composer with a pre-filled message. | | `displayHelpCenter` | Open the Intercom help center. | | `hideMessenger` | Hide the Intercom messenger. | | `displayLauncher` | Show the Intercom launcher button. | | `hideLauncher` | Hide the Intercom launcher button. | | `displayInAppMessages` | Enable in-app messages from Intercom. | | `hideInAppMessages` | Disable in-app messages from Intercom. | | `displayCarousel` | Display a specific Intercom carousel. | | `displayArticle` | Display a specific Intercom article. | | `displaySurvey` | Display a specific Intercom survey. | | `setUserHash` | Set the HMAC for identity verification. | | `setUserJwt` | Set JWT for secure messenger authentication. | | `setBottomPadding` | Set the bottom padding for the Intercom messenger UI. | | `sendPushTokenToIntercom` | Send a push notification token to Intercom. | | `receivePush` | Handle a received Intercom push notification. | | `getUnreadConversationCount` | Get the number of unread conversations for the current user. | | `addListener` | Listen for when the Intercom window is shown. | | `addListener` | Listen for when the Intercom window is hidden. | | `addListener` | Listen for changes in the unread conversation count. | | `removeAllListeners` | Remove all event listeners. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-intercom](https://github.com/Cap-go/capacitor-intercom/). # Getting Started > Install @capgo/capacitor-intercom and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-intercom bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { CapgoIntercom } from '@capgo/capacitor-intercom'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `loadWithKeys` [Section titled “loadWithKeys”](#loadwithkeys) Initialize Intercom with API keys at runtime. Use this if you prefer not to configure keys in capacitor.config. ```typescript import { CapgoIntercom } from '@capgo/capacitor-intercom'; await CapgoIntercom.loadWithKeys({} as IntercomLoadOptions); ``` ### `registerIdentifiedUser` [Section titled “registerIdentifiedUser”](#registeridentifieduser) Register a known user with Intercom. At least one of userId or email must be provided. ```typescript import { CapgoIntercom } from '@capgo/capacitor-intercom'; await CapgoIntercom.registerIdentifiedUser({} as IntercomIdentifiedUserOptions); ``` ### `registerUnidentifiedUser` [Section titled “registerUnidentifiedUser”](#registerunidentifieduser) Register an anonymous user with Intercom. ```typescript import { CapgoIntercom } from '@capgo/capacitor-intercom'; await CapgoIntercom.registerUnidentifiedUser(); ``` ### `updateUser` [Section titled “updateUser”](#updateuser) Update user attributes in Intercom. ```typescript import { CapgoIntercom } from '@capgo/capacitor-intercom'; await CapgoIntercom.updateUser({} as IntercomUserUpdateOptions); ``` ### `logout` [Section titled “logout”](#logout) Log the user out of Intercom. ```typescript import { CapgoIntercom } from '@capgo/capacitor-intercom'; await CapgoIntercom.logout(); ``` ### `logEvent` [Section titled “logEvent”](#logevent) Log a custom event in Intercom. ```typescript import { CapgoIntercom } from '@capgo/capacitor-intercom'; await CapgoIntercom.logEvent({} as IntercomLogEventOptions); ``` ### `displayMessenger` [Section titled “displayMessenger”](#displaymessenger) Open the Intercom messenger. ```typescript import { CapgoIntercom } from '@capgo/capacitor-intercom'; await CapgoIntercom.displayMessenger(); ``` ### `displayMessageComposer` [Section titled “displayMessageComposer”](#displaymessagecomposer) Open the message composer with a pre-filled message. ```typescript import { CapgoIntercom } from '@capgo/capacitor-intercom'; await CapgoIntercom.displayMessageComposer({} as IntercomMessageComposerOptions); ``` ### `displayHelpCenter` [Section titled “displayHelpCenter”](#displayhelpcenter) Open the Intercom help center. ```typescript import { CapgoIntercom } from '@capgo/capacitor-intercom'; await CapgoIntercom.displayHelpCenter(); ``` ### `hideMessenger` [Section titled “hideMessenger”](#hidemessenger) Hide the Intercom messenger. ```typescript import { CapgoIntercom } from '@capgo/capacitor-intercom'; await CapgoIntercom.hideMessenger(); ``` ### `displayLauncher` [Section titled “displayLauncher”](#displaylauncher) Show the Intercom launcher button. ```typescript import { CapgoIntercom } from '@capgo/capacitor-intercom'; await CapgoIntercom.displayLauncher(); ``` ### `hideLauncher` [Section titled “hideLauncher”](#hidelauncher) Hide the Intercom launcher button. ```typescript import { CapgoIntercom } from '@capgo/capacitor-intercom'; await CapgoIntercom.hideLauncher(); ``` ### `displayInAppMessages` [Section titled “displayInAppMessages”](#displayinappmessages) Enable in-app messages from Intercom. ```typescript import { CapgoIntercom } from '@capgo/capacitor-intercom'; await CapgoIntercom.displayInAppMessages(); ``` ### `hideInAppMessages` [Section titled “hideInAppMessages”](#hideinappmessages) Disable in-app messages from Intercom. ```typescript import { CapgoIntercom } from '@capgo/capacitor-intercom'; await CapgoIntercom.hideInAppMessages(); ``` ### `displayCarousel` [Section titled “displayCarousel”](#displaycarousel) Display a specific Intercom carousel. ```typescript import { CapgoIntercom } from '@capgo/capacitor-intercom'; await CapgoIntercom.displayCarousel({} as IntercomCarouselOptions); ``` ### `displayArticle` [Section titled “displayArticle”](#displayarticle) Display a specific Intercom article. ```typescript import { CapgoIntercom } from '@capgo/capacitor-intercom'; await CapgoIntercom.displayArticle({} as IntercomArticleOptions); ``` ### `displaySurvey` [Section titled “displaySurvey”](#displaysurvey) Display a specific Intercom survey. ```typescript import { CapgoIntercom } from '@capgo/capacitor-intercom'; await CapgoIntercom.displaySurvey({} as IntercomSurveyOptions); ``` ### `setUserHash` [Section titled “setUserHash”](#setuserhash) Set the HMAC for identity verification. ```typescript import { CapgoIntercom } from '@capgo/capacitor-intercom'; await CapgoIntercom.setUserHash({} as IntercomUserHashOptions); ``` ### `setUserJwt` [Section titled “setUserJwt”](#setuserjwt) Set JWT for secure messenger authentication. ```typescript import { CapgoIntercom } from '@capgo/capacitor-intercom'; await CapgoIntercom.setUserJwt({} as IntercomUserJwtOptions); ``` ### `setBottomPadding` [Section titled “setBottomPadding”](#setbottompadding) Set the bottom padding for the Intercom messenger UI. ```typescript import { CapgoIntercom } from '@capgo/capacitor-intercom'; await CapgoIntercom.setBottomPadding({} as IntercomBottomPaddingOptions); ``` ### `sendPushTokenToIntercom` [Section titled “sendPushTokenToIntercom”](#sendpushtokentointercom) Send a push notification token to Intercom. ```typescript import { CapgoIntercom } from '@capgo/capacitor-intercom'; await CapgoIntercom.sendPushTokenToIntercom({} as IntercomPushTokenOptions); ``` ### `receivePush` [Section titled “receivePush”](#receivepush) Handle a received Intercom push notification. ```typescript import { CapgoIntercom } from '@capgo/capacitor-intercom'; await CapgoIntercom.receivePush({} as IntercomPushNotificationData); ``` ### `getUnreadConversationCount` [Section titled “getUnreadConversationCount”](#getunreadconversationcount) Get the number of unread conversations for the current user. ```typescript import { CapgoIntercom } from '@capgo/capacitor-intercom'; await CapgoIntercom.getUnreadConversationCount(); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `IntercomLoadOptions` [Section titled “IntercomLoadOptions”](#intercomloadoptions) ```typescript export interface IntercomLoadOptions { appId?: string; apiKeyIOS?: string; apiKeyAndroid?: string; } ``` ### `IntercomIdentifiedUserOptions` [Section titled “IntercomIdentifiedUserOptions”](#intercomidentifieduseroptions) ```typescript export interface IntercomIdentifiedUserOptions { userId?: string; email?: string; } ``` ### `IntercomUserUpdateOptions` [Section titled “IntercomUserUpdateOptions”](#intercomuserupdateoptions) ```typescript export interface IntercomUserUpdateOptions { userId?: string; email?: string; name?: string; phone?: string; languageOverride?: string; customAttributes?: { [key: string]: any }; companies?: IntercomCompany[]; } ``` ### `IntercomLogEventOptions` [Section titled “IntercomLogEventOptions”](#intercomlogeventoptions) ```typescript export interface IntercomLogEventOptions { name: string; data?: { [key: string]: any }; } ``` ### `IntercomMessageComposerOptions` [Section titled “IntercomMessageComposerOptions”](#intercommessagecomposeroptions) ```typescript export interface IntercomMessageComposerOptions { message: string; } ``` ### `IntercomCarouselOptions` [Section titled “IntercomCarouselOptions”](#intercomcarouseloptions) ```typescript export interface IntercomCarouselOptions { carouselId: string; } ``` ### `IntercomArticleOptions` [Section titled “IntercomArticleOptions”](#intercomarticleoptions) ```typescript export interface IntercomArticleOptions { articleId: string; } ``` ### `IntercomSurveyOptions` [Section titled “IntercomSurveyOptions”](#intercomsurveyoptions) ```typescript export interface IntercomSurveyOptions { surveyId: string; } ``` ### `IntercomUserHashOptions` [Section titled “IntercomUserHashOptions”](#intercomuserhashoptions) ```typescript export interface IntercomUserHashOptions { hmac: string; } ``` ### `IntercomUserJwtOptions` [Section titled “IntercomUserJwtOptions”](#intercomuserjwtoptions) ```typescript export interface IntercomUserJwtOptions { jwt: string; } ``` ### `IntercomBottomPaddingOptions` [Section titled “IntercomBottomPaddingOptions”](#intercombottompaddingoptions) ```typescript export interface IntercomBottomPaddingOptions { value: number; } ``` ### `IntercomPushTokenOptions` [Section titled “IntercomPushTokenOptions”](#intercompushtokenoptions) ```typescript export interface IntercomPushTokenOptions { value: string; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-intune > Capacitor plugin for Microsoft Intune MAM enrollment, app protection policies, app config, and MSAL authentication. ## Overview [Section titled “Overview”](#overview) Capacitor plugin for Microsoft Intune MAM enrollment, app protection policies, app config, and MSAL authentication. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `acquireToken` - Present the Microsoft sign-in flow and return an access token plus the account metadata. * `acquireTokenSilent` - Acquire a token from the MSAL cache for a previously signed-in user. * `registerAndEnrollAccount` - Register a previously authenticated account with Intune and start enrollment. * `loginAndEnrollAccount` - Ask Intune to authenticate and enroll a user without first requesting an app token. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------------------ | ---------------------------------------------------------------------------------------- | | `acquireToken` | Present the Microsoft sign-in flow and return an access token plus the account metadata. | | `acquireTokenSilent` | Acquire a token from the MSAL cache for a previously signed-in user. | | `registerAndEnrollAccount` | Register a previously authenticated account with Intune and start enrollment. | | `loginAndEnrollAccount` | Ask Intune to authenticate and enroll a user without first requesting an app token. | | `enrolledAccount` | Return the currently enrolled Intune account, if one is available. | | `deRegisterAndUnenrollAccount` | Deregister the account from Intune and trigger selective wipe when applicable. | | `logoutOfAccount` | Sign the user out of MSAL without unenrolling the Intune account. | | `appConfig` | Fetch the remote Intune app configuration for a managed account. | | `getPolicy` | Fetch the currently effective Intune app protection policy for a managed account. | | `groupName` | Convenience helper that resolves the `GroupName` app configuration value when present. | | `sdkVersion` | Return the native Intune and MSAL SDK versions bundled by this plugin. | | `displayDiagnosticConsole` | Show the native Intune diagnostics UI. | | `addListener` | Listen for remote app configuration refreshes. | | `addListener` | Listen for remote app protection policy refreshes. | | `removeAllListeners` | Remove all registered listeners for this plugin instance. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-intune](https://github.com/Cap-go/capacitor-intune/). # Android Setup > Configure Microsoft Intune MAM and MSAL on Android for @capgo/capacitor-intune. ## 1. Add the Intune Gradle plugin [Section titled “1. Add the Intune Gradle plugin”](#1-add-the-intune-gradle-plugin) In your app project’s top-level `android/build.gradle`, add the Intune Gradle plugin JAR to the `buildscript` classpath. The plugin package includes: * `android/ms-intune-app-sdk-android/GradlePlugin/com.microsoft.intune.mam.build.jar` Also include the Duo Maven feed that Ionic documents for current Intune Android SDK releases: ```kotlin maven { url 'https://pkgs.dev.azure.com/MicrosoftDeviceSDK/DuoSDK-Public/_packaging/Duo-SDK-Feed/maven/v1' name 'Duo-SDK-Feed' } ``` ## 2. Update the app module [Section titled “2. Update the app module”](#2-update-the-app-module) In `android/app/build.gradle`: ```kotlin apply plugin: 'com.microsoft.intune.mam' ``` And keep resource optimization disabled: ```properties android.enableResourceOptimizations=false ``` ## 3. Provide `auth_config.json` [Section titled “3. Provide auth\_config.json”](#3-provide-auth_configjson) Create `android/app/src/main/res/raw/auth_config.json`: ```json { "client_id": "YOUR_CLIENT_ID", "authorization_user_agent": "BROWSER", "redirect_uri": "msauth://YOUR_PACKAGE/YOUR_SIGNATURE_HASH", "broker_redirect_uri_registered": true, "account_mode": "MULTIPLE", "authorities": [ { "type": "AAD", "audience": { "type": "AzureADMyOrg" } } ] } ``` The plugin expects that file at runtime for both MSAL and the Intune auth callback. ## 4. Configure the `<application>` tag [Section titled “4. Configure the \<application> tag”](#4-configure-the-application-tag) If your app does not already define a custom `Application`, set: ```xml <application android:name="app.capgo.intune.IntuneApplication" android:enableOnBackInvokedCallback="false"> ``` If you already have a custom `Application`, extend `MAMApplication` and register `IntuneMamServiceAuthenticationCallback` in `onMAMCreate()`. ## 5. Add broker auth queries and redirect handling [Section titled “5. Add broker auth queries and redirect handling”](#5-add-broker-auth-queries-and-redirect-handling) Add the package visibility queries Ionic documents for: * `com.azure.authenticator` * `com.microsoft.windowsintune.companyportal` * browser detection intents Also add `BrowserTabActivity` with your `msauth://` redirect URI host/path so MSAL can complete the sign-in round trip. ## 6. Use the plugin [Section titled “6. Use the plugin”](#6-use-the-plugin) Once the app-level native setup is complete, the Capacitor API is the same as on iOS: ```ts import { IntuneMAM } from '@capgo/capacitor-intune'; const auth = await IntuneMAM.acquireToken({ scopes: ['https://graph.microsoft.com/.default'], }); await IntuneMAM.registerAndEnrollAccount({ accountId: auth.accountId, }); ``` # Getting Started > Install and use Microsoft Intune MAM, policy, app config, and MSAL support in your Capacitor app. 1. **Install the package** ```sh bun add @capgo/capacitor-intune ``` 2. **Sync native projects** ```sh bunx cap sync ``` 3. **Complete native Intune setup** Follow the dedicated [iOS setup](/docs/plugins/intune/ios/) and [Android setup](/docs/plugins/intune/android/) pages. Intune still requires host-app native configuration for brokered auth, redirect URIs, manifests, entitlements, and MSAL config. ## Requirements [Section titled “Requirements”](#requirements) * Capacitor 8+ * Android with Intune Android SDK `12.0.3` * iOS with Intune iOS SDK `21.5.1` * iOS deployment target `17.0+` Ionic’s Intune docs currently call out a January 19, 2026 cutoff for apps built with Xcode 26, requiring Intune iOS SDK `21.1.0+`. This plugin already uses `21.5.1`. ## Basic Usage [Section titled “Basic Usage”](#basic-usage) ```ts import { IntuneMAM } from '@capgo/capacitor-intune'; await IntuneMAM.addListener('appConfigChange', (result) => { console.log('App config changed', result.accountId); }); await IntuneMAM.addListener('policyChange', (result) => { console.log('Policy changed', result.accountId); }); const auth = await IntuneMAM.acquireToken({ scopes: ['https://graph.microsoft.com/.default'], loginHint: 'alex@example.com', }); await IntuneMAM.registerAndEnrollAccount({ accountId: auth.accountId, }); const appConfig = await IntuneMAM.appConfig({ accountId: auth.accountId, }); const policy = await IntuneMAM.getPolicy({ accountId: auth.accountId, }); console.log({ auth, appConfig, policy }); ``` ## Common Flows [Section titled “Common Flows”](#common-flows) ### Interactive sign-in and enrollment [Section titled “Interactive sign-in and enrollment”](#interactive-sign-in-and-enrollment) ```ts const auth = await IntuneMAM.acquireToken({ scopes: ['https://graph.microsoft.com/.default'], }); await IntuneMAM.registerAndEnrollAccount({ accountId: auth.accountId, }); ``` ### Silent token refresh [Section titled “Silent token refresh”](#silent-token-refresh) ```ts const token = await IntuneMAM.acquireTokenSilent({ accountId: 'AAD_OBJECT_ID', scopes: ['https://graph.microsoft.com/.default'], forceRefresh: true, }); ``` ### Read the currently enrolled account [Section titled “Read the currently enrolled account”](#read-the-currently-enrolled-account) ```ts const user = await IntuneMAM.enrolledAccount(); ``` ### Sign out or selectively wipe [Section titled “Sign out or selectively wipe”](#sign-out-or-selectively-wipe) ```ts await IntuneMAM.logoutOfAccount({ accountId: 'AAD_OBJECT_ID' }); await IntuneMAM.deRegisterAndUnenrollAccount({ accountId: 'AAD_OBJECT_ID' }); ``` ## API Summary [Section titled “API Summary”](#api-summary) * `acquireToken(options)`: Start Microsoft sign-in and return token plus account metadata. * `acquireTokenSilent(options)`: Read a cached token for an existing account. * `registerAndEnrollAccount(options)`: Register the MSAL account with Intune and trigger enrollment. * `loginAndEnrollAccount()`: Let Intune drive the login and enrollment flow. * `appConfig(user)`: Read Intune app configuration values for the account. * `getPolicy(user)`: Read the current Intune app protection policy for the account. * `groupName(user)`: Read the common `GroupName` config helper value when present. * `sdkVersion()`: Inspect bundled Intune and MSAL versions. ## Platform Notes [Section titled “Platform Notes”](#platform-notes) * Web is not supported. * iOS and Android both require native project configuration beyond `cap sync`. * Your Azure registration, Intune policy assignment, redirect URIs, and entitlements remain app-specific. # iOS Setup > Configure Microsoft Intune MAM and MSAL on iOS for @capgo/capacitor-intune. ## iOS Support Matrix [Section titled “iOS Support Matrix”](#ios-support-matrix) * Intune iOS SDK bundled by this plugin: `21.5.1` * Minimum iOS version: `17.0` * Recommended Xcode line: `26.x` Ionic’s Intune docs currently note that apps built with Xcode 26 must use Intune iOS SDK `21.1.0+` starting on January 19, 2026. This plugin is already on that newer SDK line. ## 1. Add Intune and MSAL settings to `Info.plist` [Section titled “1. Add Intune and MSAL settings to Info.plist”](#1-add-intune-and-msal-settings-to-infoplist) Add an `IntuneMAMSettings` dictionary: ```xml <key>IntuneMAMSettings</key> <dict> <key>ADALClientId</key> <string>YOUR_CLIENT_ID</string> <key>ADALRedirectUri</key> <string>msauth.com.example.app://auth</string> <key>ADALAuthority</key> <string>https://login.microsoftonline.com/common</string> </dict> ``` The plugin reads: * `ADALClientId` * `ADALRedirectUri` * `ADALRedirectScheme` as a fallback if you prefer storing only the scheme * `ADALAuthority` as an optional authority override ## 2. Forward the MSAL callback in `AppDelegate` [Section titled “2. Forward the MSAL callback in AppDelegate”](#2-forward-the-msal-callback-in-appdelegate) ```swift import MSAL func application( _ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:] ) -> Bool { return MSALPublicClientApplication.handleMSALResponse( url, sourceApplication: options[.sourceApplication] as? String ) } ``` ## 3. Configure URL schemes and entitlements [Section titled “3. Configure URL schemes and entitlements”](#3-configure-url-schemes-and-entitlements) Follow Microsoft’s and Ionic’s Intune guidance for: * the `msauth...` redirect URI scheme * keychain sharing / keychain access groups * `LSApplicationQueriesSchemes` * `NSFaceIDUsageDescription` if your flow needs biometrics These are app-specific and cannot be inferred by the plugin. ## 4. Run `IntuneMAMConfigurator` [Section titled “4. Run IntuneMAMConfigurator”](#4-run-intunemamconfigurator) Microsoft requires running `IntuneMAMConfigurator` against your final app `Info.plist` and entitlements. Use the latest configurator from the official Intune iOS SDK and rerun it whenever those files materially change. ## 5. Keep the deployment target aligned [Section titled “5. Keep the deployment target aligned”](#5-keep-the-deployment-target-aligned) Because the bundled Intune iOS SDK is on the current `21.x` line, your app target should remain at iOS `17.0` or later. # @capgo/capacitor-is-root > Capacitor Is Root Plugin for detecting rooted (Android) or jailbroken (iOS) devices. ## Overview [Section titled “Overview”](#overview) Capacitor Is Root Plugin for detecting rooted (Android) or jailbroken (iOS) devices. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `isRooted` - Performs the default root/jailbreak detection checks. * `isRootedWithBusyBox` - Extends the default detection with BusyBox specific checks (Android only). * `detectRootManagementApps` - Detects if known root management applications are present (Android only). * `detectPotentiallyDangerousApps` - Detects potentially dangerous applications commonly found on rooted devices (Android only). ## Public API [Section titled “Public API”](#public-api) | Method | Description | | --------------------------------- | ------------------------------------------------------------------------------------------- | | `isRooted` | Performs the default root/jailbreak detection checks. | | `isRootedWithBusyBox` | Extends the default detection with BusyBox specific checks (Android only). | | `detectRootManagementApps` | Detects if known root management applications are present (Android only). | | `detectPotentiallyDangerousApps` | Detects potentially dangerous applications commonly found on rooted devices (Android only). | | `detectTestKeys` | Detects debug/test build tags (Android only). | | `checkForBusyBoxBinary` | Checks whether a BusyBox binary exists on the device (Android only). | | `checkForSuBinary` | Checks whether a `su` binary is present (Android only). | | `checkSuExists` | Detects if the `su` binary can be executed (Android only). | | `checkForRWPaths` | Detects world writable system paths (Android only). | | `checkForDangerousProps` | Detects dangerous system properties (Android only). | | `checkForRootNative` | Executes RootBeer native checks (Android only). | | `detectRootCloakingApps` | Detects applications that can hide root (Android only). | | `isSelinuxFlagInEnabled` | Checks the SELinux enforcement state (Android only). | | `isExistBuildTags` | Detects test build tags on the OS image (Android only). | | `doesSuperuserApkExist` | Detects if superuser APKs are installed (Android only). | | `isExistSUPath` | Checks for known `su` binary locations (Android only). | | `checkDirPermissions` | Detects writable directories that should be protected (Android only). | | `checkExecutingCommands` | Executes `which su` style commands to detect root (Android only). | | `checkInstalledPackages` | Detects suspicious installed packages (Android only). | | `checkforOverTheAirCertificates` | Detects tampered OTA certificates (Android only). | | `isRunningOnEmulator` | Detects common emulator fingerprints (Android only). | | `simpleCheckEmulator` | Performs a lightweight emulator check (Android only). | | `simpleCheckSDKBF86` | Detects x86 emulator fingerprints (Android only). | | `simpleCheckQRREFPH` | Detects QC reference phone builds (Android only). | | `simpleCheckBuild` | Detects build host anomalies (Android only). | | `checkGenymotion` | Detects Genymotion emulator fingerprints (Android only). | | `checkGeneric` | Detects generic emulator fingerprints (Android only). | | `checkGoogleSDK` | Detects Google SDK emulator fingerprints (Android only). | | `togetDeviceInfo` | Returns device information collected during detection. | | `isRootedWithEmulator` | Extends the default detection with emulator heuristics (Android only). | | `isRootedWithBusyBoxWithEmulator` | Extends the BusyBox detection with emulator heuristics (Android only). | | `getPluginVersion` | Get the native Capacitor plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-is-root](https://github.com/Cap-go/capacitor-is-root/). # Getting Started > Install @capgo/capacitor-is-root and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-is-root bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { IsRoot } from '@capgo/capacitor-is-root'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `isRooted` [Section titled “isRooted”](#isrooted) Performs the default root/jailbreak detection checks. This is the recommended method for basic root/jailbreak detection. It runs a combination of the most reliable detection heuristics for the platform. Works on both Android and iOS. ```typescript import { IsRoot } from '@capgo/capacitor-is-root'; const { result } = await IsRoot.isRooted(); if (result) { console.log('Device is rooted/jailbroken'); } else { console.log('Device is not rooted/jailbroken'); } ``` ### `isRootedWithBusyBox` [Section titled “isRootedWithBusyBox”](#isrootedwithbusybox) Extends the default detection with BusyBox specific checks (Android only). ```typescript import { IsRoot } from '@capgo/capacitor-is-root'; await IsRoot.isRootedWithBusyBox(); ``` ### `detectRootManagementApps` [Section titled “detectRootManagementApps”](#detectrootmanagementapps) Detects if known root management applications are present (Android only). ```typescript import { IsRoot } from '@capgo/capacitor-is-root'; await IsRoot.detectRootManagementApps(); ``` ### `detectPotentiallyDangerousApps` [Section titled “detectPotentiallyDangerousApps”](#detectpotentiallydangerousapps) Detects potentially dangerous applications commonly found on rooted devices (Android only). ```typescript import { IsRoot } from '@capgo/capacitor-is-root'; await IsRoot.detectPotentiallyDangerousApps(); ``` ### `detectTestKeys` [Section titled “detectTestKeys”](#detecttestkeys) Detects debug/test build tags (Android only). ```typescript import { IsRoot } from '@capgo/capacitor-is-root'; await IsRoot.detectTestKeys(); ``` ### `checkForBusyBoxBinary` [Section titled “checkForBusyBoxBinary”](#checkforbusyboxbinary) Checks whether a BusyBox binary exists on the device (Android only). ```typescript import { IsRoot } from '@capgo/capacitor-is-root'; await IsRoot.checkForBusyBoxBinary(); ``` ### `checkForSuBinary` [Section titled “checkForSuBinary”](#checkforsubinary) Checks whether a `su` binary is present (Android only). ```typescript import { IsRoot } from '@capgo/capacitor-is-root'; await IsRoot.checkForSuBinary(); ``` ### `checkSuExists` [Section titled “checkSuExists”](#checksuexists) Detects if the `su` binary can be executed (Android only). ```typescript import { IsRoot } from '@capgo/capacitor-is-root'; await IsRoot.checkSuExists(); ``` ### `checkForRWPaths` [Section titled “checkForRWPaths”](#checkforrwpaths) Detects world writable system paths (Android only). ```typescript import { IsRoot } from '@capgo/capacitor-is-root'; await IsRoot.checkForRWPaths(); ``` ### `checkForDangerousProps` [Section titled “checkForDangerousProps”](#checkfordangerousprops) Detects dangerous system properties (Android only). ```typescript import { IsRoot } from '@capgo/capacitor-is-root'; await IsRoot.checkForDangerousProps(); ``` ### `checkForRootNative` [Section titled “checkForRootNative”](#checkforrootnative) Executes RootBeer native checks (Android only). ```typescript import { IsRoot } from '@capgo/capacitor-is-root'; await IsRoot.checkForRootNative(); ``` ### `detectRootCloakingApps` [Section titled “detectRootCloakingApps”](#detectrootcloakingapps) Detects applications that can hide root (Android only). ```typescript import { IsRoot } from '@capgo/capacitor-is-root'; await IsRoot.detectRootCloakingApps(); ``` ### `isSelinuxFlagInEnabled` [Section titled “isSelinuxFlagInEnabled”](#isselinuxflaginenabled) Checks the SELinux enforcement state (Android only). ```typescript import { IsRoot } from '@capgo/capacitor-is-root'; await IsRoot.isSelinuxFlagInEnabled(); ``` ### `isExistBuildTags` [Section titled “isExistBuildTags”](#isexistbuildtags) Detects test build tags on the OS image (Android only). ```typescript import { IsRoot } from '@capgo/capacitor-is-root'; await IsRoot.isExistBuildTags(); ``` ### `doesSuperuserApkExist` [Section titled “doesSuperuserApkExist”](#doessuperuserapkexist) Detects if superuser APKs are installed (Android only). ```typescript import { IsRoot } from '@capgo/capacitor-is-root'; await IsRoot.doesSuperuserApkExist(); ``` ### `isExistSUPath` [Section titled “isExistSUPath”](#isexistsupath) Checks for known `su` binary locations (Android only). ```typescript import { IsRoot } from '@capgo/capacitor-is-root'; await IsRoot.isExistSUPath(); ``` ### `checkDirPermissions` [Section titled “checkDirPermissions”](#checkdirpermissions) Detects writable directories that should be protected (Android only). ```typescript import { IsRoot } from '@capgo/capacitor-is-root'; await IsRoot.checkDirPermissions(); ``` ### `checkExecutingCommands` [Section titled “checkExecutingCommands”](#checkexecutingcommands) Executes `which su` style commands to detect root (Android only). ```typescript import { IsRoot } from '@capgo/capacitor-is-root'; await IsRoot.checkExecutingCommands(); ``` ### `checkInstalledPackages` [Section titled “checkInstalledPackages”](#checkinstalledpackages) Detects suspicious installed packages (Android only). ```typescript import { IsRoot } from '@capgo/capacitor-is-root'; await IsRoot.checkInstalledPackages(); ``` ### `checkforOverTheAirCertificates` [Section titled “checkforOverTheAirCertificates”](#checkforovertheaircertificates) Detects tampered OTA certificates (Android only). ```typescript import { IsRoot } from '@capgo/capacitor-is-root'; await IsRoot.checkforOverTheAirCertificates(); ``` ### `isRunningOnEmulator` [Section titled “isRunningOnEmulator”](#isrunningonemulator) Detects common emulator fingerprints (Android only). ```typescript import { IsRoot } from '@capgo/capacitor-is-root'; await IsRoot.isRunningOnEmulator(); ``` ### `simpleCheckEmulator` [Section titled “simpleCheckEmulator”](#simplecheckemulator) Performs a lightweight emulator check (Android only). ```typescript import { IsRoot } from '@capgo/capacitor-is-root'; await IsRoot.simpleCheckEmulator(); ``` ### `simpleCheckSDKBF86` [Section titled “simpleCheckSDKBF86”](#simplechecksdkbf86) Detects x86 emulator fingerprints (Android only). ```typescript import { IsRoot } from '@capgo/capacitor-is-root'; await IsRoot.simpleCheckSDKBF86(); ``` ### `simpleCheckQRREFPH` [Section titled “simpleCheckQRREFPH”](#simplecheckqrrefph) Detects QC reference phone builds (Android only). ```typescript import { IsRoot } from '@capgo/capacitor-is-root'; await IsRoot.simpleCheckQRREFPH(); ``` ### `simpleCheckBuild` [Section titled “simpleCheckBuild”](#simplecheckbuild) Detects build host anomalies (Android only). ```typescript import { IsRoot } from '@capgo/capacitor-is-root'; await IsRoot.simpleCheckBuild(); ``` ### `checkGenymotion` [Section titled “checkGenymotion”](#checkgenymotion) Detects Genymotion emulator fingerprints (Android only). ```typescript import { IsRoot } from '@capgo/capacitor-is-root'; await IsRoot.checkGenymotion(); ``` ### `checkGeneric` [Section titled “checkGeneric”](#checkgeneric) Detects generic emulator fingerprints (Android only). ```typescript import { IsRoot } from '@capgo/capacitor-is-root'; await IsRoot.checkGeneric(); ``` ### `checkGoogleSDK` [Section titled “checkGoogleSDK”](#checkgooglesdk) Detects Google SDK emulator fingerprints (Android only). ```typescript import { IsRoot } from '@capgo/capacitor-is-root'; await IsRoot.checkGoogleSDK(); ``` ### `togetDeviceInfo` [Section titled “togetDeviceInfo”](#togetdeviceinfo) Returns device information collected during detection. Provides additional context and metadata about the device that was gathered during the root detection process. Useful for debugging and logging purposes. ```typescript import { IsRoot } from '@capgo/capacitor-is-root'; const deviceInfo = await IsRoot.togetDeviceInfo(); console.log('Device info:', deviceInfo); ``` ### `isRootedWithEmulator` [Section titled “isRootedWithEmulator”](#isrootedwithemulator) Extends the default detection with emulator heuristics (Android only). ```typescript import { IsRoot } from '@capgo/capacitor-is-root'; await IsRoot.isRootedWithEmulator(); ``` ### `isRootedWithBusyBoxWithEmulator` [Section titled “isRootedWithBusyBoxWithEmulator”](#isrootedwithbusyboxwithemulator) Extends the BusyBox detection with emulator heuristics (Android only). ```typescript import { IsRoot } from '@capgo/capacitor-is-root'; await IsRoot.isRootedWithBusyBoxWithEmulator(); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `DetectionResult` [Section titled “DetectionResult”](#detectionresult) Result returned by root/jailbreak detection methods. ```typescript export interface DetectionResult { /** * `true` when the associated heuristic detects root/jailbreak artifacts. * `false` when no root/jailbreak indicators are found. * * @since 1.0.0 */ result: boolean; } ``` ### `DeviceInfo` [Section titled “DeviceInfo”](#deviceinfo) Device information collected during detection. ```typescript export interface DeviceInfo { /** * Arbitrary key/value device metadata populated by the native implementation. * Contents vary by platform and detection methods used. * * @since 1.0.0 */ [key: string]: any; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-ivs-player > Ivs player for capacitor app. ## Overview [Section titled “Overview”](#overview) Ivs player for capacitor app. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `create` * `start` * `cast` * `getCastStatus` ## Public API [Section titled “Public API”](#public-api) | Method | Description | | -------------------- | ------------------------------------------------------------------------------ | | `create` | See the source definitions for current behavior. | | `start` | See the source definitions for current behavior. | | `cast` | See the source definitions for current behavior. | | `getCastStatus` | See the source definitions for current behavior. | | `pause` | See the source definitions for current behavior. | | `delete` | See the source definitions for current behavior. | | `getUrl` | See the source definitions for current behavior. | | `getState` | See the source definitions for current behavior. | | `setPlayerPosition` | See the source definitions for current behavior. | | `getPlayerPosition` | See the source definitions for current behavior. | | `setAutoQuality` | See the source definitions for current behavior. | | `getAutoQuality` | See the source definitions for current behavior. | | `setPip` | See the source definitions for current behavior. | | `getPip` | See the source definitions for current behavior. | | `setFrame` | Set the frame of the player view, all number have to be positive and integers. | | `getFrame` | See the source definitions for current behavior. | | `setBackgroundState` | See the source definitions for current behavior. | | `getBackgroundState` | See the source definitions for current behavior. | | `setMute` | See the source definitions for current behavior. | | `getMute` | See the source definitions for current behavior. | | `setQuality` | See the source definitions for current behavior. | | `getQuality` | See the source definitions for current behavior. | | `getQualities` | See the source definitions for current behavior. | | `getPluginVersion` | Get the native Capacitor plugin version. | | `addListener` | Listen for start pip. | | `addListener` | Listen for stop pip. | | `addListener` | Listen for expend pip. | | `addListener` | Listen for close pip. | | `addListener` | Listen for state changes. | | `addListener` | Listen for cue changes. | | `addListener` | Listen for duration changes. | | `addListener` | Listen for errors. | | `addListener` | Listen for rebuffering. | | `addListener` | Listen for position changes. | | `addListener` | Listen for video size changes. | | `addListener` | Listen for quality changes. | | `addListener` | Listen for cast status changes. | | `removeAllListeners` | Remove all listeners for this plugin. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-ivs-player](https://github.com/Cap-go/capacitor-ivs-player/). # Getting Started > Install @capgo/capacitor-ivs-player and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-ivs-player bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { CapacitorIvsPlayer } from '@capgo/capacitor-ivs-player'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `create` [Section titled “create”](#create) See the source definitions for the current contract. ```typescript import { CapacitorIvsPlayer } from '@capgo/capacitor-ivs-player'; await CapacitorIvsPlayer.create({} as { url: string; pip?: boolean; title?: string; subtitle?: string; cover?: string; autoPlay?: boolean; toBack?: boolean; x?: number; y?: number; width?: number; height?: number; }); ``` ### `start` [Section titled “start”](#start) See the source definitions for the current contract. ```typescript import { CapacitorIvsPlayer } from '@capgo/capacitor-ivs-player'; await CapacitorIvsPlayer.start(); ``` ### `cast` [Section titled “cast”](#cast) See the source definitions for the current contract. ```typescript import { CapacitorIvsPlayer } from '@capgo/capacitor-ivs-player'; await CapacitorIvsPlayer.cast(); ``` ### `getCastStatus` [Section titled “getCastStatus”](#getcaststatus) See the source definitions for the current contract. ```typescript import { CapacitorIvsPlayer } from '@capgo/capacitor-ivs-player'; await CapacitorIvsPlayer.getCastStatus(); ``` ### `pause` [Section titled “pause”](#pause) See the source definitions for the current contract. ```typescript import { CapacitorIvsPlayer } from '@capgo/capacitor-ivs-player'; await CapacitorIvsPlayer.pause(); ``` ### `delete` [Section titled “delete”](#delete) See the source definitions for the current contract. ```typescript import { CapacitorIvsPlayer } from '@capgo/capacitor-ivs-player'; await CapacitorIvsPlayer.delete(); ``` ### `getUrl` [Section titled “getUrl”](#geturl) See the source definitions for the current contract. ```typescript import { CapacitorIvsPlayer } from '@capgo/capacitor-ivs-player'; await CapacitorIvsPlayer.getUrl(); ``` ### `getState` [Section titled “getState”](#getstate) See the source definitions for the current contract. ```typescript import { CapacitorIvsPlayer } from '@capgo/capacitor-ivs-player'; await CapacitorIvsPlayer.getState(); ``` ### `setPlayerPosition` [Section titled “setPlayerPosition”](#setplayerposition) See the source definitions for the current contract. ```typescript import { CapacitorIvsPlayer } from '@capgo/capacitor-ivs-player'; await CapacitorIvsPlayer.setPlayerPosition(); ``` ### `getPlayerPosition` [Section titled “getPlayerPosition”](#getplayerposition) See the source definitions for the current contract. ```typescript import { CapacitorIvsPlayer } from '@capgo/capacitor-ivs-player'; await CapacitorIvsPlayer.getPlayerPosition(); ``` ### `setAutoQuality` [Section titled “setAutoQuality”](#setautoquality) See the source definitions for the current contract. ```typescript import { CapacitorIvsPlayer } from '@capgo/capacitor-ivs-player'; await CapacitorIvsPlayer.setAutoQuality(); ``` ### `getAutoQuality` [Section titled “getAutoQuality”](#getautoquality) See the source definitions for the current contract. ```typescript import { CapacitorIvsPlayer } from '@capgo/capacitor-ivs-player'; await CapacitorIvsPlayer.getAutoQuality(); ``` ### `setPip` [Section titled “setPip”](#setpip) See the source definitions for the current contract. ```typescript import { CapacitorIvsPlayer } from '@capgo/capacitor-ivs-player'; await CapacitorIvsPlayer.setPip(); ``` ### `getPip` [Section titled “getPip”](#getpip) See the source definitions for the current contract. ```typescript import { CapacitorIvsPlayer } from '@capgo/capacitor-ivs-player'; await CapacitorIvsPlayer.getPip(); ``` ### `setFrame` [Section titled “setFrame”](#setframe) Set the frame of the player view, all number have to be positive and integers ```typescript import { CapacitorIvsPlayer } from '@capgo/capacitor-ivs-player'; await CapacitorIvsPlayer.setFrame(); ``` ### `getFrame` [Section titled “getFrame”](#getframe) See the source definitions for the current contract. ```typescript import { CapacitorIvsPlayer } from '@capgo/capacitor-ivs-player'; await CapacitorIvsPlayer.getFrame(); ``` ### `setBackgroundState` [Section titled “setBackgroundState”](#setbackgroundstate) See the source definitions for the current contract. ```typescript import { CapacitorIvsPlayer } from '@capgo/capacitor-ivs-player'; await CapacitorIvsPlayer.setBackgroundState({} as { backgroundState: CapacitorIvsPlayerBackgroundState }); ``` ### `getBackgroundState` [Section titled “getBackgroundState”](#getbackgroundstate) See the source definitions for the current contract. ```typescript import { CapacitorIvsPlayer } from '@capgo/capacitor-ivs-player'; await CapacitorIvsPlayer.getBackgroundState(); ``` ### `setMute` [Section titled “setMute”](#setmute) See the source definitions for the current contract. ```typescript import { CapacitorIvsPlayer } from '@capgo/capacitor-ivs-player'; await CapacitorIvsPlayer.setMute(); ``` ### `getMute` [Section titled “getMute”](#getmute) See the source definitions for the current contract. ```typescript import { CapacitorIvsPlayer } from '@capgo/capacitor-ivs-player'; await CapacitorIvsPlayer.getMute(); ``` ### `setQuality` [Section titled “setQuality”](#setquality) See the source definitions for the current contract. ```typescript import { CapacitorIvsPlayer } from '@capgo/capacitor-ivs-player'; await CapacitorIvsPlayer.setQuality(); ``` ### `getQuality` [Section titled “getQuality”](#getquality) See the source definitions for the current contract. ```typescript import { CapacitorIvsPlayer } from '@capgo/capacitor-ivs-player'; await CapacitorIvsPlayer.getQuality(); ``` ### `getQualities` [Section titled “getQualities”](#getqualities) See the source definitions for the current contract. ```typescript import { CapacitorIvsPlayer } from '@capgo/capacitor-ivs-player'; await CapacitorIvsPlayer.getQualities(); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `CapacitorIvsPlayerState` [Section titled “CapacitorIvsPlayerState”](#capacitorivsplayerstate) ```typescript export type CapacitorIvsPlayerState = 'IDLE' | 'BUFFERING' | 'READY' | 'PLAYING' | 'ENDED' | 'UNKNOWN'; ``` ### `CapacitorIvsPlayerBackgroundState` [Section titled “CapacitorIvsPlayerBackgroundState”](#capacitorivsplayerbackgroundstate) ```typescript export type CapacitorIvsPlayerBackgroundState = 'PAUSED' | 'PLAYING'; ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-jw-player > Playes videos from jwplayer.com. ## Overview [Section titled “Overview”](#overview) Playes videos from jwplayer.com. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `initialize` - Initialize the JW Player. * `play` - Play a video. * `pause` - Pause the currently playing media. * `resume` - Resume the currently paused media. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ----------------------- | ----------------------------------------------------------- | | `initialize` | Initialize the JW Player. | | `play` | Play a video. | | `pause` | Pause the currently playing media. | | `resume` | Resume the currently paused media. | | `stop` | Stop the currently playing media. | | `seekTo` | Seek to a specific position in the currently playing media. | | `setVolume` | Set the volume level. | | `getPosition` | Get the current position in the media. | | `getState` | Get the current player state. | | `setSpeed` | Set the playback speed. | | `setPlaylistIndex` | Set the current item in the playlist by index. | | `loadPlaylist` | Load a playlist. | | `loadPlaylistWithItems` | Load a playlist with items. | | `getAudioTracks` | Get available audio tracks. | | `getCurrentAudioTrack` | Get the current audio track. | | `setCurrentAudioTrack` | Set the current audio track. | | `getCaptions` | Get the available captions/subtitles. | | `getCurrentCaptions` | Get the current captions/subtitles track. | | `setCurrentCaptions` | Set the current captions/subtitles track. | | `currentPlaylist` | Get the current playlist. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-jw-player](https://github.com/Cap-go/capacitor-jw-player/). # Getting Started > Install @capgo/capacitor-jw-player and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-jw-player bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { JwPlayer } from '@capgo/capacitor-jw-player'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `initialize` [Section titled “initialize”](#initialize) Initialize the JW Player ```typescript import { JwPlayer } from '@capgo/capacitor-jw-player'; await JwPlayer.initialize({} as { licenseKey: string; playerUrl?: string }); ``` ### `play` [Section titled “play”](#play) Play a video ```typescript import { JwPlayer } from '@capgo/capacitor-jw-player'; await JwPlayer.play({} as { mediaUrl: string; mediaType: 'video' | 'playlist'; autostart?: boolean }); ``` ### `pause` [Section titled “pause”](#pause) Pause the currently playing media ```typescript import { JwPlayer } from '@capgo/capacitor-jw-player'; await JwPlayer.pause(); ``` ### `resume` [Section titled “resume”](#resume) Resume the currently paused media ```typescript import { JwPlayer } from '@capgo/capacitor-jw-player'; await JwPlayer.resume(); ``` ### `stop` [Section titled “stop”](#stop) Stop the currently playing media ```typescript import { JwPlayer } from '@capgo/capacitor-jw-player'; await JwPlayer.stop(); ``` ### `seekTo` [Section titled “seekTo”](#seekto) Seek to a specific position in the currently playing media ```typescript import { JwPlayer } from '@capgo/capacitor-jw-player'; await JwPlayer.seekTo({} as { time: number }); ``` ### `setVolume` [Section titled “setVolume”](#setvolume) Set the volume level ```typescript import { JwPlayer } from '@capgo/capacitor-jw-player'; await JwPlayer.setVolume({} as { volume: number }); ``` ### `getPosition` [Section titled “getPosition”](#getposition) Get the current position in the media ```typescript import { JwPlayer } from '@capgo/capacitor-jw-player'; await JwPlayer.getPosition(); ``` ### `getState` [Section titled “getState”](#getstate) Get the current player state ```typescript import { JwPlayer } from '@capgo/capacitor-jw-player'; await JwPlayer.getState(); ``` ### `setSpeed` [Section titled “setSpeed”](#setspeed) Set the playback speed ```typescript import { JwPlayer } from '@capgo/capacitor-jw-player'; await JwPlayer.setSpeed({} as { speed: number }); ``` ### `setPlaylistIndex` [Section titled “setPlaylistIndex”](#setplaylistindex) Set the current item in the playlist by index ```typescript import { JwPlayer } from '@capgo/capacitor-jw-player'; await JwPlayer.setPlaylistIndex({} as { index: number }); ``` ### `loadPlaylist` [Section titled “loadPlaylist”](#loadplaylist) Load a playlist ```typescript import { JwPlayer } from '@capgo/capacitor-jw-player'; await JwPlayer.loadPlaylist({} as { playlistUrl: string }); ``` ### `loadPlaylistWithItems` [Section titled “loadPlaylistWithItems”](#loadplaylistwithitems) Load a playlist with items ```typescript import { JwPlayer } from '@capgo/capacitor-jw-player'; await JwPlayer.loadPlaylistWithItems({} as { playlist: any[] }); ``` ### `getAudioTracks` [Section titled “getAudioTracks”](#getaudiotracks) Get available audio tracks ```typescript import { JwPlayer } from '@capgo/capacitor-jw-player'; await JwPlayer.getAudioTracks(); ``` ### `getCurrentAudioTrack` [Section titled “getCurrentAudioTrack”](#getcurrentaudiotrack) Get the current audio track ```typescript import { JwPlayer } from '@capgo/capacitor-jw-player'; await JwPlayer.getCurrentAudioTrack(); ``` ### `setCurrentAudioTrack` [Section titled “setCurrentAudioTrack”](#setcurrentaudiotrack) Set the current audio track ```typescript import { JwPlayer } from '@capgo/capacitor-jw-player'; await JwPlayer.setCurrentAudioTrack({} as { index: number }); ``` ### `getCaptions` [Section titled “getCaptions”](#getcaptions) Get the available captions/subtitles ```typescript import { JwPlayer } from '@capgo/capacitor-jw-player'; await JwPlayer.getCaptions(); ``` ### `getCurrentCaptions` [Section titled “getCurrentCaptions”](#getcurrentcaptions) Get the current captions/subtitles track ```typescript import { JwPlayer } from '@capgo/capacitor-jw-player'; await JwPlayer.getCurrentCaptions(); ``` ### `setCurrentCaptions` [Section titled “setCurrentCaptions”](#setcurrentcaptions) Set the current captions/subtitles track ```typescript import { JwPlayer } from '@capgo/capacitor-jw-player'; await JwPlayer.setCurrentCaptions({} as { index: number }); ``` ### `currentPlaylist` [Section titled “currentPlaylist”](#currentplaylist) Get the current playlist ```typescript import { JwPlayer } from '@capgo/capacitor-jw-player'; await JwPlayer.currentPlaylist(); ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-keep-awake > Capacitor Keep Awake Plugin for preventing the device screen from dimming/sleeping. ## Overview [Section titled “Overview”](#overview) Capacitor Keep Awake Plugin for preventing the device screen from dimming/sleeping. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `keepAwake` - Prevent the device from dimming the screen. * `allowSleep` - Allow the device to dim the screen (disable keep awake). * `isSupported` - Check if the keep awake feature is supported on the current platform. * `isKeptAwake` - Check if the device is currently being kept awake. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------ | --------------------------------------------------------------------- | | `keepAwake` | Prevent the device from dimming the screen. | | `allowSleep` | Allow the device to dim the screen (disable keep awake). | | `isSupported` | Check if the keep awake feature is supported on the current platform. | | `isKeptAwake` | Check if the device is currently being kept awake. | | `getPluginVersion` | Get the native Capacitor plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-keep-awake](https://github.com/Cap-go/capacitor-keep-awake/). # Getting Started > Install @capgo/capacitor-keep-awake and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-keep-awake bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { KeepAwake } from '@capgo/capacitor-keep-awake'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `keepAwake` [Section titled “keepAwake”](#keepawake) Prevent the device from dimming the screen. ```typescript import { KeepAwake } from '@capgo/capacitor-keep-awake'; await KeepAwake.keepAwake(); console.log('Screen will stay awake'); ``` ### `allowSleep` [Section titled “allowSleep”](#allowsleep) Allow the device to dim the screen (disable keep awake). ```typescript import { KeepAwake } from '@capgo/capacitor-keep-awake'; await KeepAwake.allowSleep(); console.log('Screen can now dim'); ``` ### `isSupported` [Section titled “isSupported”](#issupported) Check if the keep awake feature is supported on the current platform. ```typescript import { KeepAwake } from '@capgo/capacitor-keep-awake'; const { isSupported } = await KeepAwake.isSupported(); if (isSupported) { console.log('Keep awake is supported'); } ``` ### `isKeptAwake` [Section titled “isKeptAwake”](#iskeptawake) Check if the device is currently being kept awake. ```typescript import { KeepAwake } from '@capgo/capacitor-keep-awake'; const { isKeptAwake } = await KeepAwake.isKeptAwake(); console.log('Is kept awake:', isKeptAwake); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `IsSupportedResult` [Section titled “IsSupportedResult”](#issupportedresult) Result of the isSupported() method. ```typescript export interface IsSupportedResult { /** * Whether keep awake is supported on the current platform. * * @since 1.0.0 */ isSupported: boolean; } ``` ### `IsKeptAwakeResult` [Section titled “IsKeptAwakeResult”](#iskeptawakeresult) Result of the isKeptAwake() method. ```typescript export interface IsKeptAwakeResult { /** * Whether the device is currently being kept awake. * * @since 1.0.0 */ isKeptAwake: boolean; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-launch-navigator > Main plugin interface. ## Overview [Section titled “Overview”](#overview) Main plugin interface. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `navigate` - Navigate to a location using latitude and longitude. * `isAppAvailable` - Check if a specific navigation app is available. * `getAvailableApps` - Get list of available navigation apps on the device. * `getSupportedApps` - Get list of supported apps for the current platform. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------ | ---------------------------------------------------- | | `navigate` | Navigate to a location using latitude and longitude. | | `isAppAvailable` | Check if a specific navigation app is available. | | `getAvailableApps` | Get list of available navigation apps on the device. | | `getSupportedApps` | Get list of supported apps for the current platform. | | `getDefaultApp` | Get the name of the default app for navigation. | | `getPluginVersion` | Get the native Capacitor plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-launch-navigator](https://github.com/Cap-go/capacitor-launch-navigator/). # Getting Started > Install @capgo/capacitor-launch-navigator and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-launch-navigator bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { LaunchNavigator } from '@capgo/capacitor-launch-navigator'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `navigate` [Section titled “navigate”](#navigate) Navigate to a location using latitude and longitude ```typescript import { LaunchNavigator } from '@capgo/capacitor-launch-navigator'; await LaunchNavigator.navigate({} as { /** * Destination coordinates [latitude, longitude] */ destination: [number, number]; /** * Optional navigation options */ options?: NavigateOptions; }); ``` ### `isAppAvailable` [Section titled “isAppAvailable”](#isappavailable) Check if a specific navigation app is available ```typescript import { LaunchNavigator } from '@capgo/capacitor-launch-navigator'; await LaunchNavigator.isAppAvailable({} as { /** * App identifier to check */ app: IOSNavigationApp | AndroidNavigationApp | string; }); ``` ### `getAvailableApps` [Section titled “getAvailableApps”](#getavailableapps) Get list of available navigation apps on the device ```typescript import { LaunchNavigator } from '@capgo/capacitor-launch-navigator'; await LaunchNavigator.getAvailableApps(); ``` ### `getSupportedApps` [Section titled “getSupportedApps”](#getsupportedapps) Get list of supported apps for the current platform ```typescript import { LaunchNavigator } from '@capgo/capacitor-launch-navigator'; await LaunchNavigator.getSupportedApps(); ``` ### `getDefaultApp` [Section titled “getDefaultApp”](#getdefaultapp) Get the name of the default app for navigation ```typescript import { LaunchNavigator } from '@capgo/capacitor-launch-navigator'; await LaunchNavigator.getDefaultApp(); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `NavigateOptions` [Section titled “NavigateOptions”](#navigateoptions) Options for navigation. ```typescript export interface NavigateOptions { /** * Starting location coordinates [latitude, longitude] */ start?: [number, number]; /** * Starting location name */ startName?: string; /** * Destination name (will be ignored since we only support coordinates) */ destinationName?: string; /** * Transport mode */ transportMode?: TransportMode; /** * Specific app to launch (if not specified, will use default or prompt) */ app?: IOSNavigationApp | AndroidNavigationApp | string; /** * Launch mode */ launchMode?: LaunchMode; /** * Additional parameters specific to certain apps */ extras?: Record<string, any>; /** * Enable debug logging */ enableDebug?: boolean; } ``` ### `IOSNavigationApp` [Section titled “IOSNavigationApp”](#iosnavigationapp) Available navigation apps for iOS. ```typescript export enum IOSNavigationApp { APPLE_MAPS = 'apple_maps', GOOGLE_MAPS = 'google_maps', WAZE = 'waze', CITYMAPPER = 'citymapper', GARMIN_NAVIGON = 'garmin_navigon', TRANSIT_APP = 'transit_app', YANDEX_NAVIGATOR = 'yandex', UBER = 'uber', TOMTOM = 'tomtom', SYGIC = 'sygic', HERE_MAPS = 'here', MOOVIT = 'moovit', LYFT = 'lyft', MAPS_ME = 'mapsme', CABIFY = 'cabify', BAIDU = 'baidu', GAODE = 'gaode', TAXI_99 = '99taxi', } ``` ### `AndroidNavigationApp` [Section titled “AndroidNavigationApp”](#androidnavigationapp) Available navigation apps for Android. ```typescript export enum AndroidNavigationApp { GOOGLE_MAPS = 'google_maps', WAZE = 'waze', CITYMAPPER = 'citymapper', UBER = 'uber', YANDEX = 'yandex', SYGIC = 'sygic', HERE_MAPS = 'here', MOOVIT = 'moovit', LYFT = 'lyft', MAPS_ME = 'mapsme', CABIFY = 'cabify', BAIDU = 'baidu', GAODE = 'gaode', } ``` ### `AvailableApp` [Section titled “AvailableApp”](#availableapp) Result of checking app availability. ```typescript export interface AvailableApp { /** * App identifier */ app: string; /** * Display name of the app */ name: string; /** * Whether the app is available on the device */ available: boolean; } ``` ### `TransportMode` [Section titled “TransportMode”](#transportmode) Transport modes. ```typescript export enum TransportMode { DRIVING = 'driving', WALKING = 'walking', BICYCLING = 'bicycling', TRANSIT = 'transit', } ``` ### `LaunchMode` [Section titled “LaunchMode”](#launchmode) Launch modes. ```typescript export enum LaunchMode { MAPS = 'maps', TURN_BY_TURN = 'turn_by_turn', GEO = 'geo', } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-light-sensor > Capacitor plugin for accessing the device's ambient light sensor. ## Overview [Section titled “Overview”](#overview) Capacitor plugin for accessing the device’s ambient light sensor. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `isAvailable` - Check if the light sensor is available on the current device. You should always check sensor availability before attempting to use it. * `start` - Start listening to light sensor updates. This will begin sensor measurements at the specified interval. Use `addListener` to receive the sensor data. * `stop` - Stop listening to light sensor updates. This will stop the sensor and conserve battery. * `checkPermissions` - Check the current permission status for high sampling rate sensors. On Android 12+, the HIGH\_SAMPLING\_RATE\_SENSORS permission is required for sensor update intervals below 200ms. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `isAvailable` | Check if the light sensor is available on the current device. You should always check sensor availability before attempting to use it. | | `start` | Start listening to light sensor updates. This will begin sensor measurements at the specified interval. Use `addListener` to receive the sensor data. | | `stop` | Stop listening to light sensor updates. This will stop the sensor and conserve battery. | | `addListener` | Add a listener for light sensor change events. The listener will be called whenever new sensor data is available. | | `removeAllListeners` | Remove all listeners for light sensor events. | | `checkPermissions` | Check the current permission status for high sampling rate sensors. On Android 12+, the HIGH\_SAMPLING\_RATE\_SENSORS permission is required for sensor update intervals below 200ms. | | `requestPermissions` | Request permission for high sampling rate sensors. On Android 12+, this requests the HIGH\_SAMPLING\_RATE\_SENSORS permission. | | `getPluginVersion` | Get the current version of the plugin. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-light-sensor](https://github.com/Cap-go/capacitor-light-sensor/). # Getting Started > Install @capgo/capacitor-light-sensor and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-light-sensor bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { LightSensor } from '@capgo/capacitor-light-sensor'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `isAvailable` [Section titled “isAvailable”](#isavailable) Check if the light sensor is available on the current device. You should always check sensor availability before attempting to use it. ```typescript import { LightSensor } from '@capgo/capacitor-light-sensor'; const { available } = await LightSensor.isAvailable(); ``` ### `start` [Section titled “start”](#start) Start listening to light sensor updates. This will begin sensor measurements at the specified interval. Use `addListener` to receive the sensor data. ```typescript import { LightSensor } from '@capgo/capacitor-light-sensor'; await LightSensor.start({ updateInterval: 500 }); ``` ### `stop` [Section titled “stop”](#stop) Stop listening to light sensor updates. This will stop the sensor and conserve battery. ```typescript import { LightSensor } from '@capgo/capacitor-light-sensor'; await LightSensor.stop(); ``` ### `checkPermissions` [Section titled “checkPermissions”](#checkpermissions) Check the current permission status for high sampling rate sensors. On Android 12+, the HIGH\_SAMPLING\_RATE\_SENSORS permission is required for sensor update intervals below 200ms. ```typescript import { LightSensor } from '@capgo/capacitor-light-sensor'; const status = await LightSensor.checkPermissions(); ``` ### `requestPermissions` [Section titled “requestPermissions”](#requestpermissions) Request permission for high sampling rate sensors. On Android 12+, this requests the HIGH\_SAMPLING\_RATE\_SENSORS permission. ```typescript import { LightSensor } from '@capgo/capacitor-light-sensor'; const status = await LightSensor.requestPermissions(); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `IsAvailableResult` [Section titled “IsAvailableResult”](#isavailableresult) Result indicating whether the sensor is available. ```typescript export interface IsAvailableResult { /** * Whether the light sensor is available on this device. * Always false on iOS as the light sensor API is not available. * * @since 0.0.1 */ available: boolean; } ``` ### `StartOptions` [Section titled “StartOptions”](#startoptions) Options for starting the light sensor listener. ```typescript export interface StartOptions { /** * The desired interval between sensor updates in milliseconds. * On Android 12+, there's a minimum interval of 200ms unless the app * has the HIGH_SAMPLING_RATE_SENSORS permission. * * @default 200 * @since 0.0.1 */ updateInterval?: number; } ``` ### `LightSensorCallback` [Section titled “LightSensorCallback”](#lightsensorcallback) Callback function for light sensor updates. ```typescript export type LightSensorCallback = (measurement: LightSensorMeasurement) => void; ``` ### `PermissionStatus` [Section titled “PermissionStatus”](#permissionstatus) Result of a permission request or check. ```typescript export interface PermissionStatus { /** * Whether the high sampling rate sensor permission is granted. * On Android 12+, this permission is required for update intervals below 200ms. * * @since 0.0.1 */ highSamplingRate: 'prompt' | 'prompt-with-rationale' | 'granted' | 'denied'; } ``` ### `VersionResult` [Section titled “VersionResult”](#versionresult) Plugin version information. ```typescript export interface VersionResult { /** * The current version of the plugin. * * @since 0.0.1 */ version: string; } ``` ### `LightSensorMeasurement` [Section titled “LightSensorMeasurement”](#lightsensormeasurement) A single light sensor measurement. ```typescript export interface LightSensorMeasurement { /** * Ambient light level in lux (lx). * * @since 0.0.1 */ illuminance: number; /** * Timestamp of the measurement in seconds since epoch. * * @since 0.0.1 */ timestamp: number; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-live-activities > Capacitor Live Activities Plugin interface for managing iOS Live Activities. ## Overview [Section titled “Overview”](#overview) Capacitor Live Activities Plugin interface for managing iOS Live Activities. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `areActivitiesSupported` - Check if Live Activities are supported on this device. Requires iOS 16.1+ and device support. * `startActivity` - Start a new Live Activity with the specified layout and data. * `updateActivity` - Update an existing Live Activity with new data. * `endActivity` - End a Live Activity. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `areActivitiesSupported` | Check if Live Activities are supported on this device. Requires iOS 16.1+ and device support. | | `startActivity` | Start a new Live Activity with the specified layout and data. | | `updateActivity` | Update an existing Live Activity with new data. | | `endActivity` | End a Live Activity. | | `getAllActivities` | Get all currently active Live Activities. | | `saveImage` | Save an image to the shared App Group container for use in Live Activities. Images must be saved to the shared container to be accessible from the widget extension. | | `removeImage` | Remove a saved image from the shared container. | | `listImages` | List all saved images in the shared container. | | `cleanupImages` | Remove all saved images from the shared container. | | `getPluginVersion` | Get the native Capacitor plugin version. | | `startTimerSequence` | Start a timer sequence for workouts/sports. On iOS: Shows in Live Activity and Dynamic Island On Android: Shows as a foreground notification with timer. | | `pauseTimerSequence` | Pause the timer sequence. | | `resumeTimerSequence` | Resume a paused timer sequence. | | `stopTimerSequence` | Stop and dismiss the timer sequence. | | `skipTimerStep` | Skip to the next step in the sequence. | | `previousTimerStep` | Go back to the previous step in the sequence. | | `getTimerState` | Get the current state of a timer sequence. | | `addListener` | Add a listener for timer sequence events. Events include: stepChange, complete, tick, paused, resumed, stopped, loopComplete. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-live-activities](https://github.com/Cap-go/capacitor-live-activities/). # Getting Started > Install @capgo/capacitor-live-activities and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-live-activities bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { CapgoLiveActivities } from '@capgo/capacitor-live-activities'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `areActivitiesSupported` [Section titled “areActivitiesSupported”](#areactivitiessupported) Check if Live Activities are supported on this device. Requires iOS 16.1+ and device support. ```typescript import { CapgoLiveActivities } from '@capgo/capacitor-live-activities'; const { supported, reason } = await CapgoLiveActivities.areActivitiesSupported(); if (supported) { console.log('Live Activities are supported!'); } else { console.log('Not supported:', reason); } ``` ### `startActivity` [Section titled “startActivity”](#startactivity) Start a new Live Activity with the specified layout and data. ```typescript import { CapgoLiveActivities } from '@capgo/capacitor-live-activities'; const { activityId } = await CapgoLiveActivities.startActivity({ layout: { type: 'container', direction: 'horizontal', children: [ { type: 'text', content: 'Order #{{orderNumber}}', fontSize: 16, fontWeight: 'bold' }, { type: 'text', content: '{{status}}', fontSize: 14, color: '#666666' } ] }, dynamicIslandLayout: { expanded: { leading: { type: 'image', source: 'sfSymbol', value: 'box.truck' }, trailing: { type: 'text', content: '{{eta}}' }, center: { type: 'text', content: '{{status}}' }, bottom: { type: 'progress', value: 'progress' } }, compactLeading: { type: 'image', source: 'sfSymbol', value: 'box.truck' }, compactTrailing: { type: 'text', content: '{{eta}}' }, minimal: { type: 'image', source: 'sfSymbol', value: 'box.truck' } }, data: { orderNumber: '12345', status: 'On the way', eta: '10 min', progress: 0.6 } }); console.log('Started activity:', activityId); ``` ### `updateActivity` [Section titled “updateActivity”](#updateactivity) Update an existing Live Activity with new data. ```typescript import { CapgoLiveActivities } from '@capgo/capacitor-live-activities'; await CapgoLiveActivities.updateActivity({ activityId: 'abc123', data: { status: 'Arrived!', eta: 'Now', progress: 1.0 }, alertConfiguration: { title: 'Delivery Update', body: 'Your order has arrived!' } }); ``` ### `endActivity` [Section titled “endActivity”](#endactivity) End a Live Activity. ```typescript import { CapgoLiveActivities } from '@capgo/capacitor-live-activities'; await CapgoLiveActivities.endActivity({ activityId: 'abc123', data: { status: 'Delivered' }, dismissalPolicy: 'after', dismissAfter: Date.now() + 3600000 // 1 hour from now }); ``` ### `getAllActivities` [Section titled “getAllActivities”](#getallactivities) Get all currently active Live Activities. ```typescript import { CapgoLiveActivities } from '@capgo/capacitor-live-activities'; const { activities } = await CapgoLiveActivities.getAllActivities(); activities.forEach(activity => { console.log(`Activity ${activity.activityId}: ${activity.state}`); }); ``` ### `saveImage` [Section titled “saveImage”](#saveimage) Save an image to the shared App Group container for use in Live Activities. Images must be saved to the shared container to be accessible from the widget extension. ```typescript import { CapgoLiveActivities } from '@capgo/capacitor-live-activities'; const { success, imageName } = await CapgoLiveActivities.saveImage({ imageData: 'base64EncodedImageData...', name: 'product-image', compressionQuality: 0.8 }); // Use in layout with: { type: 'image', source: 'saved', value: imageName } ``` ### `removeImage` [Section titled “removeImage”](#removeimage) Remove a saved image from the shared container. ```typescript import { CapgoLiveActivities } from '@capgo/capacitor-live-activities'; const { success } = await CapgoLiveActivities.removeImage({ name: 'product-image' }); ``` ### `listImages` [Section titled “listImages”](#listimages) List all saved images in the shared container. ```typescript import { CapgoLiveActivities } from '@capgo/capacitor-live-activities'; const { images } = await CapgoLiveActivities.listImages(); console.log('Saved images:', images); ``` ### `cleanupImages` [Section titled “cleanupImages”](#cleanupimages) Remove all saved images from the shared container. ```typescript import { CapgoLiveActivities } from '@capgo/capacitor-live-activities'; await CapgoLiveActivities.cleanupImages(); ``` ### `startTimerSequence` [Section titled “startTimerSequence”](#starttimersequence) Start a timer sequence for workouts/sports. On iOS: Shows in Live Activity and Dynamic Island On Android: Shows as a foreground notification with timer ```typescript import { CapgoLiveActivities } from '@capgo/capacitor-live-activities'; const { sequenceId } = await CapgoLiveActivities.startTimerSequence({ title: 'HIIT Workout', steps: [ { duration: 30, title: 'Jumping Jacks', subtitle: 'Warm up', color: '#FF6B00', icon: 'figure.jumprope' }, { duration: 10, title: 'Rest', color: '#00C853', icon: 'pause.circle' }, { duration: 45, title: 'Burpees', subtitle: 'High intensity', color: '#FF0000', icon: 'flame.fill' }, { duration: 15, title: 'Rest', color: '#00C853', icon: 'pause.circle' }, { duration: 45, title: 'Mountain Climbers', color: '#FF0000', icon: 'figure.run' }, { duration: 15, title: 'Rest', color: '#00C853', icon: 'pause.circle' }, ], loop: true, loopCount: 3, soundEnabled: true, vibrateEnabled: true, countdownBeeps: true, tapUrl: 'myapp://workout/hiit' }); ``` ### `pauseTimerSequence` [Section titled “pauseTimerSequence”](#pausetimersequence) Pause the timer sequence. ```typescript import { CapgoLiveActivities } from '@capgo/capacitor-live-activities'; await CapgoLiveActivities.pauseTimerSequence({ sequenceId: 'abc123' }); ``` ### `resumeTimerSequence` [Section titled “resumeTimerSequence”](#resumetimersequence) Resume a paused timer sequence. ```typescript import { CapgoLiveActivities } from '@capgo/capacitor-live-activities'; await CapgoLiveActivities.resumeTimerSequence({ sequenceId: 'abc123' }); ``` ### `stopTimerSequence` [Section titled “stopTimerSequence”](#stoptimersequence) Stop and dismiss the timer sequence. ```typescript import { CapgoLiveActivities } from '@capgo/capacitor-live-activities'; await CapgoLiveActivities.stopTimerSequence({ sequenceId: 'abc123' }); ``` ### `skipTimerStep` [Section titled “skipTimerStep”](#skiptimerstep) Skip to the next step in the sequence. ```typescript import { CapgoLiveActivities } from '@capgo/capacitor-live-activities'; await CapgoLiveActivities.skipTimerStep({ sequenceId: 'abc123' }); ``` ### `previousTimerStep` [Section titled “previousTimerStep”](#previoustimerstep) Go back to the previous step in the sequence. ```typescript import { CapgoLiveActivities } from '@capgo/capacitor-live-activities'; await CapgoLiveActivities.previousTimerStep({ sequenceId: 'abc123' }); ``` ### `getTimerState` [Section titled “getTimerState”](#gettimerstate) Get the current state of a timer sequence. ```typescript import { CapgoLiveActivities } from '@capgo/capacitor-live-activities'; const state = await CapgoLiveActivities.getTimerState({ sequenceId: 'abc123' }); console.log(`Step ${state.currentStepIndex + 1}/${state.totalSteps}: ${state.currentStep.title}`); console.log(`Time remaining: ${state.remainingSeconds}s`); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `AreActivitiesSupportedResult` [Section titled “AreActivitiesSupportedResult”](#areactivitiessupportedresult) Result of checking if activities are supported. ```typescript export interface AreActivitiesSupportedResult { /** Whether Live Activities are supported on this device */ supported: boolean; /** Reason if not supported */ reason?: string; } ``` ### `StartActivityOptions` [Section titled “StartActivityOptions”](#startactivityoptions) Options for starting a Live Activity. ```typescript export interface StartActivityOptions { /** Main activity layout (lock screen widget) */ layout: ActivityLayout; /** Dynamic Island layout configuration */ dynamicIslandLayout: DynamicIslandLayout; /** Activity behavior settings */ behavior?: LiveActivitiesBehavior; /** Dynamic data for the activity */ data: Record<string, unknown>; /** Stale date timestamp (activity becomes stale after this) */ staleDate?: number; /** Relevance score for activity ordering (0-100) */ relevanceScore?: number; } ``` ### `StartActivityResult` [Section titled “StartActivityResult”](#startactivityresult) Result of starting an activity. ```typescript export interface StartActivityResult { /** Unique activity identifier */ activityId: string; } ``` ### `UpdateActivityOptions` [Section titled “UpdateActivityOptions”](#updateactivityoptions) Options for updating a Live Activity. ```typescript export interface UpdateActivityOptions { /** Activity ID to update */ activityId: string; /** Updated data */ data: Record<string, unknown>; /** Optional alert to show with update */ alertConfiguration?: ActivityAlertConfiguration; /** Updated stale date */ staleDate?: number; /** Updated relevance score */ relevanceScore?: number; } ``` ### `EndActivityOptions` [Section titled “EndActivityOptions”](#endactivityoptions) Options for ending a Live Activity. ```typescript export interface EndActivityOptions { /** Activity ID to end */ activityId: string; /** Final data to display */ data?: Record<string, unknown>; /** Dismissal policy */ dismissalPolicy?: 'immediate' | 'default' | 'after'; /** Dismiss after timestamp (when dismissalPolicy is 'after') */ dismissAfter?: number; } ``` ### `GetAllActivitiesResult` [Section titled “GetAllActivitiesResult”](#getallactivitiesresult) Result of getAllActivities. ```typescript export interface GetAllActivitiesResult { /** List of activities */ activities: ActivityInfo[]; } ``` ### `SaveImageOptions` [Section titled “SaveImageOptions”](#saveimageoptions) Options for saving an image. ```typescript export interface SaveImageOptions { /** Base64 encoded image data */ imageData: string; /** Name to save the image as */ name: string; /** JPEG compression quality (0-1, default 0.8) */ compressionQuality?: number; } ``` ### `SaveImageResult` [Section titled “SaveImageResult”](#saveimageresult) Result of saving an image. ```typescript export interface SaveImageResult { /** Whether the save was successful */ success: boolean; /** Saved image name */ imageName: string; } ``` ### `RemoveImageOptions` [Section titled “RemoveImageOptions”](#removeimageoptions) Options for removing an image. ```typescript export interface RemoveImageOptions { /** Name of the image to remove */ name: string; } ``` ### `RemoveImageResult` [Section titled “RemoveImageResult”](#removeimageresult) Result of removing an image. ```typescript export interface RemoveImageResult { /** Whether the removal was successful */ success: boolean; } ``` ### `ListImagesResult` [Section titled “ListImagesResult”](#listimagesresult) Result of listing images. ```typescript export interface ListImagesResult { /** List of saved image names */ images: string[]; } ``` ### `TimerSequenceOptions` [Section titled “TimerSequenceOptions”](#timersequenceoptions) Options for starting a timer sequence. ```typescript export interface TimerSequenceOptions { /** Array of steps in the sequence */ steps: TimerStep[]; /** Overall title for the sequence (e.g., "HIIT Workout", "Tabata") */ title?: string; /** Whether to loop the sequence when complete */ loop?: boolean; /** Number of times to loop (if loop is true, 0 means infinite) */ loopCount?: number; /** Play sound on step change (default: true) */ soundEnabled?: boolean; /** Vibrate on step change (default: true) */ vibrateEnabled?: boolean; /** Play countdown beeps in last 3 seconds (default: true) */ countdownBeeps?: boolean; /** Deep link URL when tapping the notification/activity */ tapUrl?: string; /** Keep screen on during timer (Android only, default: false) */ keepScreenOn?: boolean; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-live-reload > Capacitor plugin to live reload Capacitor apps from a remote Vite dev server. ## Overview [Section titled “Overview”](#overview) Capacitor plugin to live reload Capacitor apps from a remote Vite dev server. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `configureServer` - Store remote dev server settings used for subsequent connections. * `connect` - Establish a WebSocket connection if one is not already active. * `disconnect` - Close the current WebSocket connection and disable auto reconnect. * `getStatus` - Returns the current connection status. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | -------------------- | ----------------------------------------------------------------------------------- | | `configureServer` | Store remote dev server settings used for subsequent connections. | | `connect` | Establish a WebSocket connection if one is not already active. | | `disconnect` | Close the current WebSocket connection and disable auto reconnect. | | `getStatus` | Returns the current connection status. | | `reload` | Trigger a full reload of the Capacitor WebView. | | `reloadFile` | Reload a single file/module if the runtime supports it (falls back to full reload). | | `addListener` | Listen to incoming reload events emitted by the server. | | `addListener` | Listen to socket status changes (connected/disconnected). | | `removeAllListeners` | Remove all registered listeners. | | `getPluginVersion` | Get the native Capacitor plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-live-reload](https://github.com/Cap-go/capacitor-live-reload/). # Getting Started > Install @capgo/capacitor-live-reload and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-live-reload bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { LiveReload } from '@capgo/capacitor-live-reload'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `configureServer` [Section titled “configureServer”](#configureserver) Store remote dev server settings used for subsequent connections. ```typescript import { LiveReload } from '@capgo/capacitor-live-reload'; await LiveReload.configureServer({} as ConfigureServerOptions); ``` ### `connect` [Section titled “connect”](#connect) Establish a WebSocket connection if one is not already active. ```typescript import { LiveReload } from '@capgo/capacitor-live-reload'; await LiveReload.connect(); ``` ### `disconnect` [Section titled “disconnect”](#disconnect) Close the current WebSocket connection and disable auto reconnect. ```typescript import { LiveReload } from '@capgo/capacitor-live-reload'; await LiveReload.disconnect(); ``` ### `getStatus` [Section titled “getStatus”](#getstatus) Returns the current connection status. ```typescript import { LiveReload } from '@capgo/capacitor-live-reload'; await LiveReload.getStatus(); ``` ### `reload` [Section titled “reload”](#reload) Trigger a full reload of the Capacitor WebView. ```typescript import { LiveReload } from '@capgo/capacitor-live-reload'; await LiveReload.reload(); ``` ### `reloadFile` [Section titled “reloadFile”](#reloadfile) Reload a single file/module if the runtime supports it (falls back to full reload). ```typescript import { LiveReload } from '@capgo/capacitor-live-reload'; await LiveReload.reloadFile({} as FileUpdatePayload); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `ConfigureServerOptions` [Section titled “ConfigureServerOptions”](#configureserveroptions) ```typescript export interface ConfigureServerOptions { /** * Base URL for the dev server (e.g. https://dev.local:5173). * When a connection is established the Capacitor WebView navigates to this URL. */ url: string; /** Optional WebSocket path override when different from /ws. */ websocketPath?: string; /** Extra headers sent when creating the WebSocket connection. */ headers?: Record<string, string>; /** Automatically reconnect when the socket closes unexpectedly. Default: true. */ autoReconnect?: boolean; /** Delay (ms) between reconnection attempts. Default: 2000. */ reconnectInterval?: number; } ``` ### `LiveReloadStatus` [Section titled “LiveReloadStatus”](#livereloadstatus) ```typescript export interface LiveReloadStatus { connected: boolean; url?: string; } ``` ### `FileUpdatePayload` [Section titled “FileUpdatePayload”](#fileupdatepayload) ```typescript export interface FileUpdatePayload { path: string; hash?: string; } ``` ### `LiveReloadEventCallback` [Section titled “LiveReloadEventCallback”](#livereloadeventcallback) ```typescript export type LiveReloadEventCallback = (event: LiveReloadEventPayload) => void; ``` ### `LiveReloadStatusCallback` [Section titled “LiveReloadStatusCallback”](#livereloadstatuscallback) ```typescript export type LiveReloadStatusCallback = (status: LiveReloadStatus) => void; ``` ### `LiveReloadEventPayload` [Section titled “LiveReloadEventPayload”](#livereloadeventpayload) ```typescript export interface LiveReloadEventPayload { type: LiveReloadMessageType; /** Populated when type === 'file-update'. */ file?: FileUpdatePayload; /** Optional human-readable message for errors or status changes. */ message?: string; } ``` ### `LiveReloadMessageType` [Section titled “LiveReloadMessageType”](#livereloadmessagetype) ```typescript export type LiveReloadMessageType = 'full-reload' | 'file-update' | 'error' | 'connected' | 'disconnected'; ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-llm > LLM Plugin interface for interacting with on-device language models. ## Overview [Section titled “Overview”](#overview) LLM Plugin interface for interacting with on-device language models. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `createChat` - Creates a new chat session. * `sendMessage` - Sends a message to the AI in a specific chat session. * `getReadiness` - Gets the readiness status of the LLM. * `setModel` - Sets the model configuration - iOS: Use “Apple Intelligence” as path for system model, or provide path to MediaPipe model - Android: Path to a MediaPipe model file (in assets or files directory). ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `createChat` | Creates a new chat session. | | `sendMessage` | Sends a message to the AI in a specific chat session. | | `getReadiness` | Gets the readiness status of the LLM. | | `setModel` | Sets the model configuration - iOS: Use “Apple Intelligence” as path for system model, or provide path to MediaPipe model - Android: Path to a MediaPipe model file (in assets or files directory). | | `downloadModel` | Downloads a model from a URL and saves it to the appropriate location - iOS: Downloads to the app’s documents directory - Android: Downloads to the app’s files directory. | | `addListener` | Adds a listener for text received from AI. | | `addListener` | Adds a listener for AI completion events. | | `addListener` | Adds a listener for model download progress events. | | `addListener` | Adds a listener for readiness status changes. | | `getPluginVersion` | Get the native Capacitor plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-llm](https://github.com/Cap-go/capacitor-llm/). # Getting Started > Install @capgo/capacitor-llm and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-llm bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { CapgoLLM } from '@capgo/capacitor-llm'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `createChat` [Section titled “createChat”](#createchat) Creates a new chat session ```typescript import { CapgoLLM } from '@capgo/capacitor-llm'; await CapgoLLM.createChat(); ``` ### `sendMessage` [Section titled “sendMessage”](#sendmessage) Sends a message to the AI in a specific chat session ```typescript import { CapgoLLM } from '@capgo/capacitor-llm'; await CapgoLLM.sendMessage({} as { chatId: string; message: string }); ``` ### `getReadiness` [Section titled “getReadiness”](#getreadiness) Gets the readiness status of the LLM ```typescript import { CapgoLLM } from '@capgo/capacitor-llm'; await CapgoLLM.getReadiness(); ``` ### `setModel` [Section titled “setModel”](#setmodel) Sets the model configuration * iOS: Use “Apple Intelligence” as path for system model, or provide path to MediaPipe model * Android: Path to a MediaPipe model file (in assets or files directory) ```typescript import { CapgoLLM } from '@capgo/capacitor-llm'; await CapgoLLM.setModel({} as ModelOptions); ``` ### `downloadModel` [Section titled “downloadModel”](#downloadmodel) Downloads a model from a URL and saves it to the appropriate location * iOS: Downloads to the app’s documents directory * Android: Downloads to the app’s files directory ```typescript import { CapgoLLM } from '@capgo/capacitor-llm'; await CapgoLLM.downloadModel({} as DownloadModelOptions); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `ModelOptions` [Section titled “ModelOptions”](#modeloptions) Model configuration options. ```typescript export interface ModelOptions { /** Model path or "Apple Intelligence" for iOS system model */ path: string; /** Model file type/extension (e.g., "task", "bin", "litertlm"). If not provided, will be extracted from path. */ modelType?: string; /** Maximum number of tokens the model handles */ maxTokens?: number; /** Number of tokens the model considers at each step */ topk?: number; /** Amount of randomness in generation (0.0-1.0) */ temperature?: number; /** Random seed for generation */ randomSeed?: number; } ``` ### `DownloadModelOptions` [Section titled “DownloadModelOptions”](#downloadmodeloptions) Options for downloading a model. ```typescript export interface DownloadModelOptions { /** URL of the model file to download */ url: string; /** Optional: URL of companion file (e.g., .litertlm for Android) */ companionUrl?: string; /** Optional: Custom filename (defaults to filename from URL) */ filename?: string; } ``` ### `DownloadModelResult` [Section titled “DownloadModelResult”](#downloadmodelresult) Result of model download. ```typescript export interface DownloadModelResult { /** Path where the model was saved */ path: string; /** Path where the companion file was saved (if applicable) */ companionPath?: string; } ``` ### `TextFromAiEvent` [Section titled “TextFromAiEvent”](#textfromaievent) Event data for text received from AI. ```typescript export interface TextFromAiEvent { /** The text content from AI - this is an incremental chunk, not the full text */ text: string; /** The chat session ID */ chatId: string; /** Whether this is a complete chunk (true) or partial streaming data (false) */ isChunk?: boolean; } ``` ### `AiFinishedEvent` [Section titled “AiFinishedEvent”](#aifinishedevent) Event data for AI completion. ```typescript export interface AiFinishedEvent { /** The chat session ID that finished */ chatId: string; } ``` ### `DownloadProgressEvent` [Section titled “DownloadProgressEvent”](#downloadprogressevent) Event data for download progress. ```typescript export interface DownloadProgressEvent { /** Percentage of download completed (0-100) */ progress: number; /** Total bytes to download */ totalBytes?: number; /** Bytes downloaded so far */ downloadedBytes?: number; } ``` ### `ReadinessChangeEvent` [Section titled “ReadinessChangeEvent”](#readinesschangeevent) Event data for readiness status changes. ```typescript export interface ReadinessChangeEvent { /** The readiness status */ readiness: string; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-media-session > Capacitor plugin to expose media session controls of the device. ## Overview [Section titled “Overview”](#overview) Capacitor plugin to expose media session controls of the device. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `setMetadata` - Sets metadata of the currently playing media. * `setPlaybackState` - Updates the playback state of the media session. * `setActionHandler` - Registers a handler for a media session action. * `setPositionState` - Updates position state for the active media session. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------ | ---------------------------------------------------- | | `setMetadata` | Sets metadata of the currently playing media. | | `setPlaybackState` | Updates the playback state of the media session. | | `setActionHandler` | Registers a handler for a media session action. | | `setPositionState` | Updates position state for the active media session. | | `getPluginVersion` | Get the native Capacitor plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-media-session](https://github.com/Cap-go/capacitor-media-session/). # Getting Started > Install @capgo/capacitor-media-session and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-media-session bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { MediaSession } from '@capgo/capacitor-media-session'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `setMetadata` [Section titled “setMetadata”](#setmetadata) Sets metadata of the currently playing media. ```typescript import { MediaSession } from '@capgo/capacitor-media-session'; await MediaSession.setMetadata({} as MetadataOptions); ``` ### `setPlaybackState` [Section titled “setPlaybackState”](#setplaybackstate) Updates the playback state of the media session. ```typescript import { MediaSession } from '@capgo/capacitor-media-session'; await MediaSession.setPlaybackState({} as PlaybackStateOptions); ``` ### `setActionHandler` [Section titled “setActionHandler”](#setactionhandler) Registers a handler for a media session action. ```typescript import { MediaSession } from '@capgo/capacitor-media-session'; await MediaSession.setActionHandler({} as ActionHandlerOptions, {} as ActionHandler | null); ``` ### `setPositionState` [Section titled “setPositionState”](#setpositionstate) Updates position state for the active media session. ```typescript import { MediaSession } from '@capgo/capacitor-media-session'; await MediaSession.setPositionState({} as PositionStateOptions); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `MetadataOptions` [Section titled “MetadataOptions”](#metadataoptions) ```typescript export interface MetadataOptions { album?: string; artist?: string; artwork?: MediaImage[]; title?: string; } ``` ### `PlaybackStateOptions` [Section titled “PlaybackStateOptions”](#playbackstateoptions) ```typescript export interface PlaybackStateOptions { playbackState: MediaSessionPlaybackState; } ``` ### `ActionHandlerOptions` [Section titled “ActionHandlerOptions”](#actionhandleroptions) ```typescript export interface ActionHandlerOptions { action: MediaSessionAction; } ``` ### `ActionHandler` [Section titled “ActionHandler”](#actionhandler) ```typescript export type ActionHandler = (details: ActionDetails) => void; ``` ### `PositionStateOptions` [Section titled “PositionStateOptions”](#positionstateoptions) ```typescript export interface PositionStateOptions { duration?: number; playbackRate?: number; position?: number; } ``` ### `MediaImage` [Section titled “MediaImage”](#mediaimage) ```typescript export interface MediaImage { src: string; sizes?: string; type?: string; } ``` ### `MediaSessionPlaybackState` [Section titled “MediaSessionPlaybackState”](#mediasessionplaybackstate) ```typescript export type MediaSessionPlaybackState = 'none' | 'paused' | 'playing'; ``` ### `MediaSessionAction` [Section titled “MediaSessionAction”](#mediasessionaction) ```typescript export type MediaSessionAction = | 'play' | 'pause' | 'seekbackward' | 'seekforward' | 'previoustrack' | 'nexttrack' | 'seekto' | 'stop'; ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-mqtt > Capacitor plugin for MQTT connectivity on Android and iOS. ## Overview [Section titled “Overview”](#overview) Capacitor plugin for MQTT connectivity on Android and iOS. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `connect` * `disconnect` * `subscribe` * `publish` ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------- | ------------------------------------------------ | | `connect` | See the source definitions for current behavior. | | `disconnect` | See the source definitions for current behavior. | | `subscribe` | See the source definitions for current behavior. | | `publish` | See the source definitions for current behavior. | | `addListener` | See the source definitions for current behavior. | | `addListener` | See the source definitions for current behavior. | | `addListener` | See the source definitions for current behavior. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-mqtt](https://github.com/Cap-go/capacitor-mqtt/). # Getting Started > Install @capgo/capacitor-mqtt and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-mqtt bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { MqttBridge } from '@capgo/capacitor-mqtt'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `connect` [Section titled “connect”](#connect) See the source definitions for the current contract. ```typescript import { MqttBridge } from '@capgo/capacitor-mqtt'; await MqttBridge.connect({} as { serverURI: string; port: number; clientId: string; username: string; password: string; setCleanSession: boolean; connectionTimeout: number; keepAliveInterval: number; setAutomaticReconnect: boolean; setLastWill?: { willTopic: string; willPayload: string; willQoS: number; setRetained: boolean; }; }); ``` ### `disconnect` [Section titled “disconnect”](#disconnect) See the source definitions for the current contract. ```typescript import { MqttBridge } from '@capgo/capacitor-mqtt'; await MqttBridge.disconnect(); ``` ### `subscribe` [Section titled “subscribe”](#subscribe) See the source definitions for the current contract. ```typescript import { MqttBridge } from '@capgo/capacitor-mqtt'; await MqttBridge.subscribe({} as { topic: string; qos: number }); ``` ### `publish` [Section titled “publish”](#publish) See the source definitions for the current contract. ```typescript import { MqttBridge } from '@capgo/capacitor-mqtt'; await MqttBridge.publish({} as { topic: string; payload: string; qos: number; retained: boolean }); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `onConnectionLostListener` [Section titled “onConnectionLostListener”](#onconnectionlostlistener) ```typescript export type onConnectionLostListener = (x: { connectionStatus: string; reasonCode: number; message: string }) => void; ``` ### `onConnectCompleteListener` [Section titled “onConnectCompleteListener”](#onconnectcompletelistener) ```typescript export type onConnectCompleteListener = (x: { reconnected: boolean; serverURI: string }) => void; ``` ### `onMessageArrivedListener` [Section titled “onMessageArrivedListener”](#onmessagearrivedlistener) ```typescript export type onMessageArrivedListener = (x: { topic: string; message: string }) => void; ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-mute > Capacitor Mute Plugin for detecting device mute status. ## Overview [Section titled “Overview”](#overview) Capacitor Mute Plugin for detecting device mute status. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `isMuted` - Check if the device mute switch is enabled. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------ | ------------------------------------------- | | `isMuted` | Check if the device mute switch is enabled. | | `getPluginVersion` | Get the native Capacitor plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-mute](https://github.com/Cap-go/capacitor-mute/). # Getting Started > Install @capgo/capacitor-mute and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-mute bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { Mute } from '@capgo/capacitor-mute'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `isMuted` [Section titled “isMuted”](#ismuted) Check if the device mute switch is enabled. ```typescript import { Mute } from '@capgo/capacitor-mute'; const { value } = await Mute.isMuted(); if (value) { console.log('Device is muted'); } else { console.log('Device is not muted'); } ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `MuteResponse` [Section titled “MuteResponse”](#muteresponse) Response from mute status check. ```typescript export interface MuteResponse { /** True if device is muted, false otherwise */ value: boolean; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-mux-player > Native Mux Player SDK to play video on IOS and Android. ## Overview [Section titled “Overview”](#overview) Native Mux Player SDK to play video on IOS and Android. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `play` - Launch the native Mux Player in fullscreen and begin playback. * `dismiss` - Dismiss the player if it is visible. * `isActive` - Returns whether the player is currently being displayed. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | -------------------- | -------------------------------------------------------------------- | | `play` | Launch the native Mux Player in fullscreen and begin playback. | | `dismiss` | Dismiss the player if it is visible. | | `isActive` | Returns whether the player is currently being displayed. | | `removeAllListeners` | Remove all event listeners registered on the plugin instance. | | `addListener` | Listen to player lifecycle or playback events emitted by the plugin. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-mux-player](https://github.com/Cap-go/capacitor-mux-player/). # Getting Started > Install @capgo/capacitor-mux-player and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-mux-player bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { MuxPlayer } from '@capgo/capacitor-mux-player'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `play` [Section titled “play”](#play) Launch the native Mux Player in fullscreen and begin playback. ```typescript import { MuxPlayer } from '@capgo/capacitor-mux-player'; await MuxPlayer.play({} as MuxPlayOptions); ``` ### `dismiss` [Section titled “dismiss”](#dismiss) Dismiss the player if it is visible. ```typescript import { MuxPlayer } from '@capgo/capacitor-mux-player'; await MuxPlayer.dismiss(); ``` ### `isActive` [Section titled “isActive”](#isactive) Returns whether the player is currently being displayed. ```typescript import { MuxPlayer } from '@capgo/capacitor-mux-player'; await MuxPlayer.isActive(); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `MuxPlayOptions` [Section titled “MuxPlayOptions”](#muxplayoptions) ```typescript export interface MuxPlayOptions { /** * The playback ID of the asset you want to stream. */ playbackId: string; /** * Provide a JSON web token generated for signed playback policies. */ playbackToken?: string; /** * Provide a JSON web token generated for DRM playback policies. */ drmToken?: string; /** * Override the default Mux playback domain (e.g. `stream.example.com`). */ customDomain?: string; /** * Auto-play when the player becomes visible. Defaults to true. */ autoPlay?: boolean; /** * Start playback from the provided time (in seconds). */ startTime?: number; /** * Provide a poster image URL to display before playback begins. */ poster?: string; /** * Provide a custom title to surface in native player chrome when available. */ title?: string; /** * Provide a subtitle or description to surface in native player chrome when available. */ subtitle?: string; /** * Set to true to keep the video muted when playback starts. */ muted?: boolean; /** * Mux Data environment key used for analytics. If omitted, the SDK default is used. */ environmentKey?: string; /** * Provide an explicit player name for analytics. Defaults to a generated name. */ playerName?: string; /** * Enable smart caching when the underlying SDK supports it. */ enableSmartCache?: boolean; /** * Enable verbose logging in native SDKs where available. */ debug?: boolean; } ``` ### `MuxPlayerEvents` [Section titled “MuxPlayerEvents”](#muxplayerevents) ```typescript export interface MuxPlayerEvents { /** * Fired when the underlying player is ready to begin playback. */ ready: { playerName?: string }; /** * Fired when playback starts or resumes. */ play: void; /** * Fired when playback pauses. */ pause: void; /** * Fired when playback ends. */ ended: void; /** * Fired when an unrecoverable error occurs. */ error: { message: string }; /** * Fired when the fullscreen player is closed. */ playerDismissed: void; /** * Get the native Capacitor plugin version * * @returns {Promise<{ id: string }>} an Promise with version for this device * @throws An error if the something went wrong */ getPluginVersion(): Promise<{ version: string }>; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/native-audio > A native plugin for native audio engine. ## Overview [Section titled “Overview”](#overview) A native plugin for native audio engine. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `configure` - Configure the audio player. * `preload` - Load an audio file. * `playOnce` - Play an audio file once with automatic cleanup. * `isPreloaded` - Check if an audio file is preloaded. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `configure` | Configure the audio player. | | `preload` | Load an audio file. | | `playOnce` | Play an audio file once with automatic cleanup. | | `isPreloaded` | Check if an audio file is preloaded. | | `play` | Play an audio file. | | `pause` | Pause an audio file. | | `resume` | Resume an audio file. | | `loop` | Stop an audio file. | | `stop` | Stop an audio file. | | `unload` | Unload an audio file. | | `setVolume` | Set the volume of an audio file. | | `setRate` | Set the rate of an audio file. | | `setCurrentTime` | Set the current time of an audio file. | | `getCurrentTime` | Get the current time of an audio file. | | `getDuration` | Get the duration of an audio file in seconds. | | `isPlaying` | Check if an audio file is playing. | | `addListener` | Listen for complete event. | | `addListener` | Listen for current time updates Emits every 100ms while audio is playing. | | `addListener` | Listen for playback state changes, including notification and lock-screen transport controls. Emitted by Android and iOS. The current Web implementation does not emit this event. | | `clearCache` | Clear the audio cache for remote audio files. | | `setDebugMode` | Set debug mode logging. | | `getPluginVersion` | Get the native Capacitor plugin version. | | `deinitPlugin` | Deinitialize the plugin and restore original audio session settings This method stops all playing audio and reverts any audio session changes made by the plugin Use this when you need to ensure compatibility with other audio plugins. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-native-audio](https://github.com/Cap-go/capacitor-native-audio/). # Getting Started > Install @capgo/native-audio and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/native-audio bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { NativeAudio } from '@capgo/native-audio'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `configure` [Section titled “configure”](#configure) Configure the audio player ```typescript import { NativeAudio } from '@capgo/native-audio'; await NativeAudio.configure({} as ConfigureOptions); ``` ### `preload` [Section titled “preload”](#preload) Load an audio file ```typescript import { NativeAudio } from '@capgo/native-audio'; await NativeAudio.preload({} as PreloadOptions); ``` ### `playOnce` [Section titled “playOnce”](#playonce) Play an audio file once with automatic cleanup Method designed for simple, single-shot audio playback, such as notification sounds, UI feedback, or other short audio clips that don’t require manual state management. **Key Features:** * **Fire-and-forget**: No need to manually preload, play, stop, or unload * **Auto-cleanup**: Asset is automatically unloaded after playback completes * **Optional file deletion**: Can delete local files after playback (useful for temp files) * **Returns assetId**: Can still control playback if needed (pause, stop, etc.) **Use Cases:** * Notification sounds * UI sound effects (button clicks, alerts) * Short audio clips that play once * Temporary audio files that should be cleaned up **Comparison with regular play():** * `play()`: Requires manual preload, play, and unload steps * `playOnce()`: Handles everything automatically with a single call ```typescript import { NativeAudio } from '@capgo/native-audio'; // Simple one-shot playback await NativeAudio.playOnce({ assetPath: 'audio/notification.mp3' }); // Play and delete the file after completion await NativeAudio.playOnce({ assetPath: 'file:///path/to/temp/audio.mp3', isUrl: true, deleteAfterPlay: true }); // Get the assetId to control playback const { assetId } = await NativeAudio.playOnce({ assetPath: 'audio/long-track.mp3', autoPlay: true }); // Later, you can stop it manually if needed await NativeAudio.stop({ assetId }); ``` ### `isPreloaded` [Section titled “isPreloaded”](#ispreloaded) Check if an audio file is preloaded ```typescript import { NativeAudio } from '@capgo/native-audio'; await NativeAudio.isPreloaded({} as PreloadOptions); ``` ### `play` [Section titled “play”](#play) Play an audio file ```typescript import { NativeAudio } from '@capgo/native-audio'; await NativeAudio.play({} as AssetPlayOptions); ``` ### `pause` [Section titled “pause”](#pause) Pause an audio file ```typescript import { NativeAudio } from '@capgo/native-audio'; await NativeAudio.pause({} as AssetPauseOptions); ``` ### `resume` [Section titled “resume”](#resume) Resume an audio file ```typescript import { NativeAudio } from '@capgo/native-audio'; await NativeAudio.resume({} as AssetResumeOptions); ``` ### `loop` [Section titled “loop”](#loop) Stop an audio file ```typescript import { NativeAudio } from '@capgo/native-audio'; await NativeAudio.loop({} as Assets); ``` ### `stop` [Section titled “stop”](#stop) Stop an audio file ```typescript import { NativeAudio } from '@capgo/native-audio'; await NativeAudio.stop({} as AssetStopOptions); ``` ### `unload` [Section titled “unload”](#unload) Unload an audio file ```typescript import { NativeAudio } from '@capgo/native-audio'; await NativeAudio.unload({} as Assets); ``` ### `setVolume` [Section titled “setVolume”](#setvolume) Set the volume of an audio file ```typescript import { NativeAudio } from '@capgo/native-audio'; await NativeAudio.setVolume({} as AssetVolume); ``` ### `setRate` [Section titled “setRate”](#setrate) Set the rate of an audio file ```typescript import { NativeAudio } from '@capgo/native-audio'; await NativeAudio.setRate({} as AssetRate); ``` ### `setCurrentTime` [Section titled “setCurrentTime”](#setcurrenttime) Set the current time of an audio file ```typescript import { NativeAudio } from '@capgo/native-audio'; await NativeAudio.setCurrentTime({} as AssetSetTime); ``` ### `getCurrentTime` [Section titled “getCurrentTime”](#getcurrenttime) Get the current time of an audio file ```typescript import { NativeAudio } from '@capgo/native-audio'; await NativeAudio.getCurrentTime({} as Assets); ``` ### `getDuration` [Section titled “getDuration”](#getduration) Get the duration of an audio file in seconds ```typescript import { NativeAudio } from '@capgo/native-audio'; await NativeAudio.getDuration({} as Assets); ``` ### `isPlaying` [Section titled “isPlaying”](#isplaying) Check if an audio file is playing ```typescript import { NativeAudio } from '@capgo/native-audio'; await NativeAudio.isPlaying({} as Assets); ``` ### `clearCache` [Section titled “clearCache”](#clearcache) Clear the audio cache for remote audio files ```typescript import { NativeAudio } from '@capgo/native-audio'; await NativeAudio.clearCache(); ``` ### `setDebugMode` [Section titled “setDebugMode”](#setdebugmode) Set debug mode logging ```typescript import { NativeAudio } from '@capgo/native-audio'; await NativeAudio.setDebugMode({} as { enabled: boolean }); ``` ### `deinitPlugin` [Section titled “deinitPlugin”](#deinitplugin) Deinitialize the plugin and restore original audio session settings This method stops all playing audio and reverts any audio session changes made by the plugin Use this when you need to ensure compatibility with other audio plugins ```typescript import { NativeAudio } from '@capgo/native-audio'; await NativeAudio.deinitPlugin(); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `ConfigureOptions` [Section titled “ConfigureOptions”](#configureoptions) ````typescript export interface ConfigureOptions { /** * focus the audio with Audio Focus */ focus?: boolean; /** * Play the audio in the background */ background?: boolean; /** * Ignore silent mode, works only on iOS setting this will nuke other audio apps */ ignoreSilent?: boolean; /** * Show audio playback in the notification center (iOS and Android) * When enabled, displays audio metadata (title, artist, album, artwork) in the system notification * and Control Center (iOS) or lock screen. * * **Important iOS Behavior:** * Enabling this option changes the audio session category to `.playback` with `.default` mode, * which means your app's audio will **interrupt** other apps' audio (like background music from * Spotify, Apple Music, etc.) instead of mixing with it. This is required for the Now Playing * info to appear in Control Center and on the lock screen. * * **Trade-offs:** * - `showNotification: true` → Shows Now Playing controls, but interrupts other audio * - `showNotification: false` → Audio mixes with other apps, but no Now Playing controls * * Use this when your app is the primary audio source (music players, podcast apps, etc.). * Disable this for secondary audio like sound effects or notification sounds where mixing * with background music is preferred. * * @see https://github.com/Cap-go/capacitor-native-audio/issues/202 */ showNotification?: boolean; /** * Enable background audio playback (Android only) * * When enabled, audio will continue playing when the app is backgrounded or the screen is locked. * The plugin will skip the automatic pause/resume logic that normally occurs when the app * enters the background or returns to the foreground. * * **Important Android Requirements:** * To use background playback on Android, your app must: * 1. Declare the required permissions in `AndroidManifest.xml`: * - `<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />` * - `<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />` * - `<uses-permission android:name="android.permission.WAKE_LOCK" />` * 2. Start a Foreground Service with a media-style notification before backgrounding * (the plugin does not automatically create or manage the foreground service) * 3. Use `showNotification: true` to display playback controls in the notification * * **Usage Example:** * ```typescript * await NativeAudio.configure({ * backgroundPlayback: true, * showNotification: true * }); * // Start your foreground service here * // Then preload and play audio as normal * ``` * * @default false * @platform Android * @since 8.2.0 */ backgroundPlayback?: boolean; } ```` ### `PreloadOptions` [Section titled “PreloadOptions”](#preloadoptions) ```typescript export interface PreloadOptions { /** * Path to the audio file, relative path of the file, absolute url (file://) or remote url (https://) * Supported formats: * - MP3, WAV (all platforms) * - M3U8/HLS streams (iOS and Android) */ assetPath: string; /** * Asset Id, unique identifier of the file */ assetId: string; /** * Volume of the audio, between 0.1 and 1.0 */ volume?: number; /** * Audio channel number, default is 1 */ audioChannelNum?: number; /** * Is the audio file a URL, pass true if assetPath is a `file://` url * or a streaming URL (m3u8) */ isUrl?: boolean; /** * Metadata to display in the notification center when audio is playing. * Only used when `showNotification: true` is set in `configure()`. * * See {@link ConfigureOptions.showNotification} for important details about * how this affects audio mixing behavior on iOS. * * @see NotificationMetadata */ notificationMetadata?: NotificationMetadata; /** * Custom HTTP headers to include when fetching remote audio files. * Only used when isUrl is true and assetPath is a remote URL (http/https). * Example: { 'x-api-key': 'abc123', 'Authorization': 'Bearer token' } * * @since 7.10.0 */ headers?: Record<string, string>; } ``` ### `PlayOnceOptions` [Section titled “PlayOnceOptions”](#playonceoptions) ```typescript export interface PlayOnceOptions { /** * Path to the audio file, relative path of the file, absolute url (file://) or remote url (https://) * Supported formats: * - MP3, WAV (all platforms) * - M3U8/HLS streams (iOS and Android) */ assetPath: string; /** * Volume of the audio, between 0.1 and 1.0 * @default 1.0 */ volume?: number; /** * Is the audio file a URL, pass true if assetPath is a `file://` url * or a streaming URL (m3u8) * @default false */ isUrl?: boolean; /** * Automatically start playback after loading * @default true */ autoPlay?: boolean; /** * Delete the audio file from disk after playback completes * Only works for local files (file:// URLs), ignored for remote URLs * @default false * @since 7.11.0 */ deleteAfterPlay?: boolean; /** * Metadata to display in the notification center when audio is playing. * Only used when `showNotification: true` is set in `configure()`. * * See {@link ConfigureOptions.showNotification} for important details about * how this affects audio mixing behavior on iOS. * * @see NotificationMetadata * @since 7.10.0 */ notificationMetadata?: NotificationMetadata; /** * Custom HTTP headers to include when fetching remote audio files. * Only used when isUrl is true and assetPath is a remote URL (http/https). * Example: { 'x-api-key': 'abc123', 'Authorization': 'Bearer token' } * * @since 7.10.0 */ headers?: Record<string, string>; } ``` ### `PlayOnceResult` [Section titled “PlayOnceResult”](#playonceresult) ```typescript export interface PlayOnceResult { /** * The internally generated asset ID for this playback * Can be used to control playback (pause, stop, etc.) before completion */ assetId: string; } ``` ### `AssetPlayOptions` [Section titled “AssetPlayOptions”](#assetplayoptions) ```typescript export interface AssetPlayOptions { /** * Asset Id, unique identifier of the file */ assetId: string; /** * Time to start playing the audio, in seconds */ time?: number; /** * Delay to start playing the audio, in seconds */ delay?: number; /** * Volume of the audio, between 0.1 and 1.0 */ volume?: number; /** * Whether to fade in the audio */ fadeIn?: boolean; /** * Whether to fade out the audio */ fadeOut?: boolean; /** * Fade in duration in seconds. * Only used if fadeIn is true. * Default is 1s. */ fadeInDuration?: number; /** * Fade out duration in seconds. * Only used if fadeOut is true. * Default is 1s. */ fadeOutDuration?: number; /** * Time in seconds from the start of the audio to start fading out. * Only used if fadeOut is true. * Default is fadeOutDuration before end of audio. */ fadeOutStartTime?: number; } ``` ### `AssetPauseOptions` [Section titled “AssetPauseOptions”](#assetpauseoptions) ```typescript export interface AssetPauseOptions { /** * Asset Id, unique identifier of the file */ assetId: string; /** * Whether to fade out the audio before pausing */ fadeOut?: boolean; /** * Fade out duration in seconds. * Default is 1s. */ fadeOutDuration?: number; } ``` ### `AssetResumeOptions` [Section titled “AssetResumeOptions”](#assetresumeoptions) ```typescript export interface AssetResumeOptions { /** * Asset Id, unique identifier of the file */ assetId: string; /** * Whether to fade in the audio during resume */ fadeIn?: boolean; /** * Fade in duration in seconds. * Default is 1s. */ fadeInDuration?: number; } ``` ### `Assets` [Section titled “Assets”](#assets) ```typescript export interface Assets { /** * Asset Id, unique identifier of the file */ assetId: string; } ``` ### `AssetStopOptions` [Section titled “AssetStopOptions”](#assetstopoptions) ```typescript export interface AssetStopOptions { /** * Asset Id, unique identifier of the file */ assetId: string; /** * Whether to fade out the audio before stopping */ fadeOut?: boolean; /** * Fade out duration in seconds. * Default is 1s. */ fadeOutDuration?: number; } ``` ### `AssetVolume` [Section titled “AssetVolume”](#assetvolume) ```typescript export interface AssetVolume { /** * Asset Id, unique identifier of the file */ assetId: string; /** * Volume of the audio, between 0.1 and 1.0 */ volume: number; /** * Time over which to fade to the target volume, in seconds. Default is 0s (immediate). */ duration?: number; } ``` ### `AssetRate` [Section titled “AssetRate”](#assetrate) ```typescript export interface AssetRate { /** * Asset Id, unique identifier of the file */ assetId: string; /** * Rate of the audio, between 0.1 and 1.0 */ rate: number; } ``` ### `AssetSetTime` [Section titled “AssetSetTime”](#assetsettime) ```typescript export interface AssetSetTime { /** * Asset Id, unique identifier of the file */ assetId: string; /** * Time to set the audio, in seconds */ time: number; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-native-biometric > This plugin gives access to the native biometric apis for android and iOS. ## Overview [Section titled “Overview”](#overview) This plugin gives access to the native biometric apis for android and iOS. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `isAvailable` - Checks if biometric authentication hardware is available. * `verifyIdentity` - Prompts the user to authenticate with biometrics. * `getCredentials` - Gets the stored credentials for a given server. * `setCredentials` - Stores the given credentials for a given server. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `isAvailable` | Checks if biometric authentication hardware is available. | | `addListener` | Adds a listener that is called when the app resumes from background. This is useful to detect if biometry availability has changed while the app was in the background (e.g., user enrolled/unenrolled biometrics). | | `verifyIdentity` | Prompts the user to authenticate with biometrics. | | `getCredentials` | Gets the stored credentials for a given server. | | `setCredentials` | Stores the given credentials for a given server. | | `deleteCredentials` | Deletes the stored credentials for a given server. | | `getSecureCredentials` | Gets the stored credentials for a given server, requiring biometric authentication. Credentials must have been stored with accessControl set to BIOMETRY\_CURRENT\_SET or BIOMETRY\_ANY. | | `isCredentialsSaved` | Checks if credentials are already saved for a given server. | | `getPluginVersion` | Get the native Capacitor plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-native-biometric](https://github.com/Cap-go/capacitor-native-biometric/). # Getting Started > Install @capgo/capacitor-native-biometric and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-native-biometric bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { NativeBiometric } from '@capgo/capacitor-native-biometric'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `isAvailable` [Section titled “isAvailable”](#isavailable) Checks if biometric authentication hardware is available. ```typescript import { NativeBiometric } from '@capgo/capacitor-native-biometric'; await NativeBiometric.isAvailable(); ``` ### `verifyIdentity` [Section titled “verifyIdentity”](#verifyidentity) Prompts the user to authenticate with biometrics. ```typescript import { NativeBiometric } from '@capgo/capacitor-native-biometric'; await NativeBiometric.verifyIdentity(); ``` ### `getCredentials` [Section titled “getCredentials”](#getcredentials) Gets the stored credentials for a given server. ```typescript import { NativeBiometric } from '@capgo/capacitor-native-biometric'; await NativeBiometric.getCredentials({} as GetCredentialOptions); ``` ### `setCredentials` [Section titled “setCredentials”](#setcredentials) Stores the given credentials for a given server. ```typescript import { NativeBiometric } from '@capgo/capacitor-native-biometric'; await NativeBiometric.setCredentials({} as SetCredentialOptions); ``` ### `deleteCredentials` [Section titled “deleteCredentials”](#deletecredentials) Deletes the stored credentials for a given server. ```typescript import { NativeBiometric } from '@capgo/capacitor-native-biometric'; await NativeBiometric.deleteCredentials({} as DeleteCredentialOptions); ``` ### `getSecureCredentials` [Section titled “getSecureCredentials”](#getsecurecredentials) Gets the stored credentials for a given server, requiring biometric authentication. Credentials must have been stored with accessControl set to BIOMETRY\_CURRENT\_SET or BIOMETRY\_ANY. On iOS, the system automatically shows the biometric prompt when accessing the protected Keychain item. On Android, BiometricPrompt is shown with a CryptoObject bound to the credential decryption key. ```typescript import { NativeBiometric } from '@capgo/capacitor-native-biometric'; await NativeBiometric.getSecureCredentials({} as GetSecureCredentialsOptions); ``` ### `isCredentialsSaved` [Section titled “isCredentialsSaved”](#iscredentialssaved) Checks if credentials are already saved for a given server. ```typescript import { NativeBiometric } from '@capgo/capacitor-native-biometric'; await NativeBiometric.isCredentialsSaved({} as IsCredentialsSavedOptions); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `IsAvailableOptions` [Section titled “IsAvailableOptions”](#isavailableoptions) ```typescript export interface IsAvailableOptions { /** * Only for iOS. * Specifies if should fallback to passcode authentication if biometric authentication is not available. * On Android, this parameter is ignored due to BiometricPrompt API constraints: * DEVICE_CREDENTIAL authenticator and negative button (cancel) are mutually exclusive. */ useFallback: boolean; } ``` ### `AvailableResult` [Section titled “AvailableResult”](#availableresult) Result from isAvailable() method indicating biometric authentication availability. ```typescript export interface AvailableResult { /** * Whether authentication is available (biometric or fallback if useFallback is true) */ isAvailable: boolean; /** * The strength of available authentication method (STRONG, WEAK, or NONE) */ authenticationStrength: AuthenticationStrength; /** * The primary biometry type available on the device. * On Android devices with multiple biometry types, this returns MULTIPLE. * Use this for display purposes only - always use isAvailable for logic decisions. */ biometryType: BiometryType; /** * Whether the device has a secure lock screen (PIN, pattern, or password). * This is independent of biometric enrollment. */ deviceIsSecure: boolean; /** * Whether strong biometry (Face ID, Touch ID, or fingerprint on devices that consider it strong) * is specifically available, separate from weak biometry or device credentials. */ strongBiometryIsAvailable: boolean; /** * Error code from BiometricAuthError enum. Only present when isAvailable is false. * Indicates why biometric authentication is not available. * @see BiometricAuthError */ errorCode?: BiometricAuthError; } ``` ### `BiometryChangeListener` [Section titled “BiometryChangeListener”](#biometrychangelistener) Callback type for biometry change listener. ```typescript export type BiometryChangeListener = (result: AvailableResult) => void; ``` ### `BiometricOptions` [Section titled “BiometricOptions”](#biometricoptions) ```typescript export interface BiometricOptions { reason?: string; title?: string; subtitle?: string; description?: string; negativeButtonText?: string; /** * Only for iOS. * Specifies if should fallback to passcode authentication if biometric authentication fails. * On Android, this parameter is ignored due to BiometricPrompt API constraints: * DEVICE_CREDENTIAL authenticator and negative button (cancel) are mutually exclusive. */ useFallback?: boolean; /** * Only for iOS. * Set the text for the fallback button in the authentication dialog. * If this property is not specified, the default text is set by the system. */ fallbackTitle?: string; /** * Only for Android. * Set a maximum number of attempts for biometric authentication. The maximum allowed by android is 5. * @default 1 */ maxAttempts?: number; /** * Only for Android. * Specify which biometry types are allowed for authentication. * If not specified, all available types will be allowed. * @example [BiometryType.FINGERPRINT, BiometryType.FACE_AUTHENTICATION] */ allowedBiometryTypes?: BiometryType[]; } ``` ### `GetCredentialOptions` [Section titled “GetCredentialOptions”](#getcredentialoptions) ```typescript export interface GetCredentialOptions { server: string; } ``` ### `Credentials` [Section titled “Credentials”](#credentials) ```typescript export interface Credentials { username: string; password: string; } ``` ### `SetCredentialOptions` [Section titled “SetCredentialOptions”](#setcredentialoptions) ```typescript export interface SetCredentialOptions { username: string; password: string; server: string; /** * Access control level for the stored credentials. * When set to BIOMETRY_CURRENT_SET or BIOMETRY_ANY, the credentials are * hardware-protected and require biometric authentication to access. * * On iOS, this adds SecAccessControl to the Keychain item. * On Android, this creates a biometric-protected Keystore key and requires * BiometricPrompt authentication for both storing and retrieving credentials. * * @default AccessControl.NONE * @since 8.4.0 */ accessControl?: AccessControl; } ``` ### `DeleteCredentialOptions` [Section titled “DeleteCredentialOptions”](#deletecredentialoptions) ```typescript export interface DeleteCredentialOptions { server: string; } ``` ### `GetSecureCredentialsOptions` [Section titled “GetSecureCredentialsOptions”](#getsecurecredentialsoptions) ```typescript export interface GetSecureCredentialsOptions { server: string; /** * Reason for requesting biometric authentication. * Displayed in the biometric prompt on both iOS and Android. */ reason?: string; /** * Title for the biometric prompt. * Only for Android. */ title?: string; /** * Subtitle for the biometric prompt. * Only for Android. */ subtitle?: string; /** * Description for the biometric prompt. * Only for Android. */ description?: string; /** * Text for the negative/cancel button. * Only for Android. */ negativeButtonText?: string; } ``` ### `IsCredentialsSavedOptions` [Section titled “IsCredentialsSavedOptions”](#iscredentialssavedoptions) ```typescript export interface IsCredentialsSavedOptions { server: string; } ``` ### `IsCredentialsSavedResult` [Section titled “IsCredentialsSavedResult”](#iscredentialssavedresult) ```typescript export interface IsCredentialsSavedResult { isSaved: boolean; } ``` ### `AuthenticationStrength` [Section titled “AuthenticationStrength”](#authenticationstrength) ```typescript export enum AuthenticationStrength { /** * No authentication available, even if PIN is available but useFallback = false */ NONE = 0, /** * Strong authentication: Face ID on iOS, fingerprints on devices that consider fingerprints strong (Android). * Note: PIN/pattern/password is NEVER considered STRONG, even when useFallback = true. */ STRONG = 1, /** * Weak authentication: Face authentication on Android devices that consider face weak, * or PIN/pattern/password if useFallback = true (PIN is always WEAK, never STRONG). */ WEAK = 2, } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/native-market > Capacitor Native Market Plugin for opening app store listings and pages. ## Overview [Section titled “Overview”](#overview) Capacitor Native Market Plugin for opening app store listings and pages. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `openStoreListing` - Launch app listing page in Play Store (Android) or App Store (iOS). * `openDevPage` - Deep-link directly to a developer’s page in the Play Store. Android only. * `openCollection` - Link users to a collection or top charts in the Play Store. Android only. * `openEditorChoicePage` - Link users to Editor’s choice page in the Play Store. Android only. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ---------------------- | ------------------------------------------------------------------------- | | `openStoreListing` | Launch app listing page in Play Store (Android) or App Store (iOS). | | `openDevPage` | Deep-link directly to a developer’s page in the Play Store. Android only. | | `openCollection` | Link users to a collection or top charts in the Play Store. Android only. | | `openEditorChoicePage` | Link users to Editor’s choice page in the Play Store. Android only. | | `search` | Search the Play Store with custom search terms. Android only. | | `getPluginVersion` | Get the native Capacitor plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-native-market](https://github.com/Cap-go/capacitor-native-market/). # Getting Started > Install @capgo/native-market and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/native-market bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { NativeMarket } from '@capgo/native-market'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `openStoreListing` [Section titled “openStoreListing”](#openstorelisting) Launch app listing page in Play Store (Android) or App Store (iOS). ```typescript import { NativeMarket } from '@capgo/native-market'; // Open app in store await NativeMarket.openStoreListing({ appId: 'com.example.app' }); // Open app in specific country store (iOS only) await NativeMarket.openStoreListing({ appId: 'com.example.app', country: 'IT' }); ``` ### `openDevPage` [Section titled “openDevPage”](#opendevpage) Deep-link directly to a developer’s page in the Play Store. Android only. ```typescript import { NativeMarket } from '@capgo/native-market'; await NativeMarket.openDevPage({ devId: 'Google+LLC' }); ``` ### `openCollection` [Section titled “openCollection”](#opencollection) Link users to a collection or top charts in the Play Store. Android only. ```typescript import { NativeMarket } from '@capgo/native-market'; await NativeMarket.openCollection({ name: 'featured' }); ``` ### `openEditorChoicePage` [Section titled “openEditorChoicePage”](#openeditorchoicepage) Link users to Editor’s choice page in the Play Store. Android only. ```typescript import { NativeMarket } from '@capgo/native-market'; await NativeMarket.openEditorChoicePage({ editorChoice: 'editorial_fitness_apps_us' }); ``` ### `search` [Section titled “search”](#search) Search the Play Store with custom search terms. Android only. ```typescript import { NativeMarket } from '@capgo/native-market'; await NativeMarket.search({ terms: 'fitness apps' }); ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/native-navigation > Render iOS and Android navigation chrome natively while JavaScript keeps owning routes, content, icons, labels, and bar state. Native chrome Draw the top navigation bar and bottom tab bar with platform UI instead of web components. Web-owned routes Native emits user intent events, then your existing router changes the WebView content. Serialized icons Configure tabs and buttons with SVG, SF Symbol, bundled image, or Android drawable descriptors. Native transition shell Capture the current WebView, update content in JavaScript, then finish with a native snapshot-to-WebView animation. ## Core API [Section titled “Core API”](#core-api) * `configure(options?)` enables the native chrome host and controls content insets. * `setNavbar(options)` updates native title, subtitle, back button, buttons, colors, transparency, and visibility. * `setTabbar(options)` updates tabs, selected tab, badges, labels, icons, colors, and visibility. * `beginTransition(options?)` captures the outgoing WebView before the JavaScript route change. * `finishTransition(options?)` animates from the captured snapshot to the live WebView after route content is ready. * `getPluginVersion()` returns the native implementation version marker. ## Events [Section titled “Events”](#events) * `navbarBack` fires when the native back affordance is tapped. * `navbarItemTap` fires when a native navbar action button is tapped. * `tabSelect` fires when a native tab is selected. * `safeAreaChanged` reports native bar and safe-area inset changes. * `transitionStart` and `transitionEnd` report native transition boundaries. ## Platform Model [Section titled “Platform Model”](#platform-model) iOS uses `UINavigationBar` and `UITabBar`. On iOS 26 and newer, the plugin lets the system render Liquid Glass behavior; older versions use native translucent/material fallbacks. Android uses an AppCompat toolbar and Material bottom navigation with edge-to-edge placement. The plugin does not create one native WebView per route. Version 1 keeps a single Capacitor WebView for bridge stability and lets native own only the frame, bar visuals, tab selection chrome, safe-area reporting, and transition shell. # Getting Started > Install @capgo/native-navigation and render native navigation chrome over a Capacitor WebView. 1. **Install the package** ```sh bun add @capgo/native-navigation ``` 2. **Sync native projects** ```sh bunx cap sync ``` 3. **Configure native chrome** ```ts import { NativeNavigation } from '@capgo/native-navigation'; await NativeNavigation.configure({ contentInsetMode: 'css', animationDuration: 360, colors: { tint: '#0f172a', inactiveTint: '#64748b', }, }); ``` 4. **Render the native navbar** ```ts await NativeNavigation.setNavbar({ title: 'Home', subtitle: 'Native chrome', transparent: true, backButton: { visible: false }, rightItems: [ { id: 'compose', title: 'Compose', icon: { svg: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 20h9"/><path d="M16.5 3.5a2.12 2.12 0 0 1 3 3L7 19l-4 1 1-4Z"/></svg>', }, }, ], }); ``` 5. **Render the native tabbar** ```ts await NativeNavigation.setTabbar({ selectedId: 'home', labels: true, icons: true, tabs: [ { id: 'home', title: 'Home', icon: { svg: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 10.5 12 3l9 7.5"/><path d="M5 10v10h14V10"/></svg>', }, }, { id: 'settings', title: 'Settings', badge: '2', icon: { svg: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="3"/><path d="M12 2v3M12 19v3M2 12h3M19 12h3"/></svg>', }, }, ], }); ``` 6. **Handle native intent events** ```ts await NativeNavigation.addListener('navbarBack', () => { router.back(); }); await NativeNavigation.addListener('navbarItemTap', ({ id }) => { if (id === 'compose') router.push('/compose'); }); await NativeNavigation.addListener('tabSelect', ({ id }) => { router.push(`/${id}`); }); ``` ## Transition flow [Section titled “Transition flow”](#transition-flow) Native transitions are a transaction around your normal JavaScript route change: ```ts const transition = await NativeNavigation.beginTransition({ direction: 'forward', }); router.push('/detail'); await router.ready?.(); await NativeNavigation.setNavbar({ title: 'Detail', backButton: { visible: true, title: 'Back' }, }); await NativeNavigation.finishTransition({ id: transition.id, direction: 'forward', }); ``` ## CSS insets [Section titled “CSS insets”](#css-insets) With `contentInsetMode: 'css'`, the plugin writes native bar dimensions to `document.documentElement`. ```css .page { padding-top: var(--cap-native-navigation-top); padding-bottom: var(--cap-native-navigation-bottom); } ``` Available variables: * `--cap-native-navigation-top` * `--cap-native-navigation-right` * `--cap-native-navigation-bottom` * `--cap-native-navigation-left` * `--cap-native-navbar-height` * `--cap-native-tabbar-height` ## Icon descriptors [Section titled “Icon descriptors”](#icon-descriptors) Icons must be serializable because native UI renders them. You can use cross-platform SVG, platform-specific SVG, SF Symbols, bundled iOS images, Android drawable resources, or bundled Android images. ```ts const icon = { svg: '<svg viewBox="0 0 24 24"><path d="M3 10.5 12 3l9 7.5"/></svg>', width: 24, height: 24, template: true, src: 'fallback_asset_name', ios: { svg: '<svg viewBox="0 0 24 24"><path d="M3 10.5 12 3l9 7.5"/></svg>', sfSymbol: 'house.fill', image: 'BundledAssetName', }, android: { svg: '<svg viewBox="0 0 24 24"><path d="M3 10.5 12 3l9 7.5"/></svg>', resource: 'ic_menu_view', image: 'bundled_drawable_name', }, }; ``` Inline SVG supports the icon-focused subset used by common icon sets such as Lucide and Feather: `path`, `line`, `polyline`, `polygon`, `circle`, and `rect`. SVG icons are rendered as template images by default, so native tint colors can recolor them. ## Optional web components [Section titled “Optional web components”](#optional-web-components) The package can register custom elements for framework-agnostic declarative setup: ```ts import { defineNativeNavigationElements } from '@capgo/native-navigation'; defineNativeNavigationElements(); ``` ```html <cap-native-navigation-provider enabled="true" content-inset-mode="css"></cap-native-navigation-provider> <cap-native-navbar title="Home" transparent right-items='[{"id":"compose","title":"Compose","icon":{"svg":"<svg viewBox=\"0 0 24 24\"><path d=\"M12 20h9\"/></svg>"}}]' ></cap-native-navbar> <cap-native-tabbar selected-id="home" tabs='[{"id":"home","title":"Home","icon":{"ios":{"sfSymbol":"house.fill"}}}]' ></cap-native-tabbar> ``` Note The web components are optional. React, Vue, Angular, Svelte, Solid, and vanilla apps can all use the imperative API directly. ## Platform notes [Section titled “Platform notes”](#platform-notes) * iOS renders `UINavigationBar` and `UITabBar`; iOS 26+ uses the system Liquid Glass bar behavior. * Android renders an AppCompat toolbar and Material bottom navigation. * Web fallback does not draw native bars. It mirrors events and inset variables for browser development. * The plugin keeps one full-screen Capacitor WebView. Native owns the frame, bars, safe-area reporting, and transition shell. # @capgo/native-purchases > In-app Subscriptions Made Easy. ## Overview [Section titled “Overview”](#overview) In-app Subscriptions Made Easy. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `restorePurchases` - Restores a user’s previous and links their appUserIDs to any user’s also using those . * `getAppTransaction` - Gets the App Transaction information, which provides details about when the user originally downloaded or purchased the app. * `isEntitledToOldBusinessModel` - Compares the original app version from the App Transaction against a target version to determine if the user is entitled to features from an earlier business model. * `purchaseProduct` - Started purchase process for the given product. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `restorePurchases` | Restores a user’s previous and links their appUserIDs to any user’s also using those . | | `getAppTransaction` | Gets the App Transaction information, which provides details about when the user originally downloaded or purchased the app. | | `isEntitledToOldBusinessModel` | Compares the original app version from the App Transaction against a target version to determine if the user is entitled to features from an earlier business model. | | `purchaseProduct` | Started purchase process for the given product. | | `getProducts` | Gets the product info associated with a list of product identifiers. | | `getProduct` | Gets the product info for a single product identifier. | | `isBillingSupported` | Check if billing is supported for the current device. | | `getPluginVersion` | Get the native Capacitor plugin version. | | `getPurchases` | Gets all the user’s purchases (both in-app purchases and subscriptions). This method queries the platform’s purchase history for the current user. | | `manageSubscriptions` | Opens the platform’s native subscription management page. This allows users to view, modify, or cancel their subscriptions. | | `acknowledgePurchase` | Manually acknowledge/finish a purchase transaction. | | `consumePurchase` | Consume an in-app purchase on Android. | | `addListener` | Listen for StoreKit transaction updates delivered by Apple’s Transaction.updates. Fires on app launch if there are unfinished transactions, and for any updates afterward. iOS only. | | `addListener` | Listen for StoreKit transaction verification failures delivered by Apple’s Transaction.updates. Fires when the verification result is unverified. iOS only. | | `removeAllListeners` | Remove all registered listeners. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-native-purchases](https://github.com/Cap-go/capacitor-native-purchases/). # Create Android Auto-Renewable Subscription > Step-by-step guide to creating auto-renewable subscriptions in Google Play Console for the native-purchases plugin. Auto-renewable subscriptions provide access to content, services, or premium features in your app on an ongoing basis. This guide will help you create and configure subscriptions in Google Play Console. ## Overview [Section titled “Overview”](#overview) Subscriptions automatically renew at the end of each billing period until the user cancels. They’re ideal for: * Premium content access * Ad-free experiences * Cloud storage * Ongoing services ## Creating a Subscription [Section titled “Creating a Subscription”](#creating-a-subscription) 1. **Navigate to Subscriptions** In Google Play Console, select your app and choose **Monetize > Subscriptions** from the left menu. Click the **Create subscription** button to begin. ![Navigate to subscriptions](/native-purchases/android/create-subscription/navigate-to-subscriptions.webp) 2. **Enter Basic Information** Provide a subscription name and product ID. The product ID is required for configuration in your app and cannot be changed later. ![Enter subscription details](/native-purchases/android/create-subscription/enter-subscription-details.webp) 3. **Create Base Plan** Google Play requires exactly one base plan per subscription. The native-purchases plugin supports only one base plan to maintain compatibility with iOS. Click **Add base plan** to continue. ![Create base plan](/native-purchases/android/create-subscription/create-base-plan.webp) 4. **Configure Base Plan Details** Enter: * **Base plan ID**: Unique identifier for this plan * **Billing period**: How often users are charged (weekly, monthly, yearly, etc.) * **Grace period**: Time window during which Google maintains the subscription while retrying payment before cancellation ![Configure base plan](/native-purchases/android/create-subscription/configure-base-plan-details.webp) 5. **Set Up Pricing** Access the pricing section and select all countries/regions where you want to offer the subscription. ![Select regions](/native-purchases/android/create-subscription/select-pricing-regions.webp) 6. **Configure Price** Set your base price in your primary currency. Google Play automatically converts this to local currencies. ![Set price](/native-purchases/android/create-subscription/set-base-price.webp) 7. **Review Regional Pricing** Review the automatically converted prices for each country. You can adjust individual prices if needed. ![Review pricing](/native-purchases/android/create-subscription/review-regional-pricing.webp) 8. **Save Configuration** Save your pricing configuration. ![Save pricing](/native-purchases/android/create-subscription/save-pricing-configuration.webp) 9. **Activate Subscription** Click the **Activate** button to make your subscription product live and available for purchase. ![Activate subscription](/native-purchases/android/create-subscription/activate-subscription.webp) ## Important Considerations [Section titled “Important Considerations”](#important-considerations) ### Base Plan Limitation [Section titled “Base Plan Limitation”](#base-plan-limitation) The native-purchases plugin requires exactly one base plan per subscription to ensure consistency with iOS subscription handling. Multiple base plans are not supported. ### Grace Period [Section titled “Grace Period”](#grace-period) The grace period allows Google Play to retry failed payments while maintaining the user’s subscription access. Common grace periods are: * 3 days for monthly subscriptions * 7 days for longer subscriptions ### Subscription Status [Section titled “Subscription Status”](#subscription-status) After creation, your subscription will be in “Draft” status until activated. You can test draft subscriptions in sandbox mode. ## Using in Your App [Section titled “Using in Your App”](#using-in-your-app) Once created, reference the subscription in your app using the product ID: ```typescript import { NativePurchases, PURCHASE_TYPE } from '@capgo/native-purchases'; // Load subscription info const { products } = await NativePurchases.getProducts({ productIdentifiers: ['com.example.premium.monthly'], productType: PURCHASE_TYPE.SUBS, }); const product = products[0]; console.log(`${product.title} — ${product.priceString}`); // Purchase (planIdentifier = Base Plan ID from Google Play Console) const transaction = await NativePurchases.purchaseProduct({ productIdentifier: 'com.example.premium.monthly', planIdentifier: 'monthly-plan', // REQUIRED on Android, ignored on iOS productType: PURCHASE_TYPE.SUBS, }); console.log('Transaction ID', transaction.transactionId); // Later, check purchase state const { purchases } = await NativePurchases.getPurchases({ productType: PURCHASE_TYPE.SUBS, }); const subscription = purchases.find( (purchase) => purchase.productIdentifier === 'com.example.premium.monthly', ); if (subscription && subscription.purchaseState === 'PURCHASED' && subscription.isAcknowledged) { console.log('Subscription active locally'); // For expiration/cancellation, validate purchaseToken through your backend } ``` ## Next Steps [Section titled “Next Steps”](#next-steps) * [Create an introductory offer](/docs/plugins/native-purchases/android-introductory-offer/) to attract new subscribers * [Configure sandbox testing](/docs/plugins/native-purchases/android-sandbox-testing/) to test your subscriptions * Set up backend receipt validation for security ## Troubleshooting [Section titled “Troubleshooting”](#troubleshooting) **Subscription not appearing in app:** * Verify the product ID matches exactly * Ensure the subscription is activated * Check that your app has the correct package name * Wait 2-3 hours after activation for changes to propagate **Base plan errors:** * Ensure you have exactly one base plan * Verify all required fields are filled * Check that billing period is valid **Pricing issues:** * Confirm at least one country is selected * Verify base price is greater than minimum allowed * Check currency conversion rates are acceptable # Create Android Subscription Introductory Offer > Learn how to create introductory offers for auto-renewable subscriptions on Android to attract new subscribers. Introductory offers allow you to provide eligible users with either a free trial or a discounted introductory price. After the introductory period concludes, subscriptions automatically renew at standard pricing unless cancelled. ## Overview [Section titled “Overview”](#overview) Introductory offers are a powerful tool to: * Reduce barriers to entry for new subscribers * Increase conversion rates * Allow users to try your premium features risk-free * Build long-term subscriber relationships ## Eligibility [Section titled “Eligibility”](#eligibility) Users can receive an introductory offer if they haven’t previously purchased or received an introductory offer for the subscription. Google Play handles eligibility automatically. ## Prerequisites [Section titled “Prerequisites”](#prerequisites) You must first [create an auto-renewable subscription](/docs/plugins/native-purchases/android-create-subscription/) before adding an introductory offer. ## Creating an Introductory Offer [Section titled “Creating an Introductory Offer”](#creating-an-introductory-offer) 1. **Access Offer Configuration** Navigate to your subscription in Google Play Console and select the **Add offer** button. ![Add offer button](/native-purchases/android/introductory-offer/add-offer-button.webp) 2. **Select Base Plan** A modal will appear requiring you to choose your base plan. Typically, you’ll only have one base plan. Click **Add offer** to continue. ![Select base plan](/native-purchases/android/introductory-offer/select-base-plan.webp) 3. **Configure Offer Details** Enter the following information: **Offer ID**: A unique identifier for this offer **Eligibility**: Choose who can receive this offer * **New customers**: Only users who have never subscribed * **Existing customers**: Users who previously subscribed * **Developer determined**: Custom eligibility logic (not supported by native-purchases) Caution The native-purchases plugin does not support the “Developer determined” eligibility option. Use “New customers” or “Existing customers” instead. ![Configure offer](/native-purchases/android/introductory-offer/configure-offer-details.webp) 4. **Add Phases** Click **Add phase** at the bottom of the page to define your offer structure. You can add up to two phases, allowing combinations like: * Free trial only * Discounted price only * Free trial followed by discounted recurring payment 5. **Select Phase Type** Choose from three phase types: **Free Trial** * Complimentary access for a set duration * Example: 7 days free, then $9.99/month **Single Payment** * One-time discounted price for a specific period * Example: $1.99 for 2 months, then $9.99/month **Discounted Recurring Payment** * Reduced per-billing-cycle rate for multiple cycles * Example: $4.99/month for 3 months, then $9.99/month 6. **Configure Phase Duration** Set how long the introductory phase lasts: * Days, weeks, or months * Number of billing cycles 7. **Finalize and Activate** Click **Apply**, then **Save** to activate the offer. The **Activate** button will become available once saved. ## Offer Phase Examples [Section titled “Offer Phase Examples”](#offer-phase-examples) ### Example 1: Simple Free Trial [Section titled “Example 1: Simple Free Trial”](#example-1-simple-free-trial) * Phase 1: 7 days free * Then: $9.99/month standard pricing ### Example 2: Discounted Introduction [Section titled “Example 2: Discounted Introduction”](#example-2-discounted-introduction) * Phase 1: $1.99 for the first month * Then: $9.99/month standard pricing ### Example 3: Extended Trial + Discount [Section titled “Example 3: Extended Trial + Discount”](#example-3-extended-trial--discount) * Phase 1: 14 days free * Phase 2: $4.99/month for 2 months * Then: $9.99/month standard pricing ## Using in Your App [Section titled “Using in Your App”](#using-in-your-app) The native-purchases plugin automatically handles introductory offer eligibility and presentation: ```typescript import { NativePurchases, PURCHASE_TYPE } from '@capgo/native-purchases'; // Fetch products (includes intro offer metadata) const { products } = await NativePurchases.getProducts({ productIdentifiers: ['com.example.premium.monthly'], productType: PURCHASE_TYPE.SUBS, }); const product = products[0]; if (product.introductoryPrice) { console.log(`Intro price: ${product.introductoryPriceString}`); console.log(`Regular price: ${product.priceString}`); console.log( `Offer duration: ${product.introductoryPrice.subscriptionPeriod?.numberOfUnits} ${product.introductoryPrice.subscriptionPeriod?.unit}`, ); } else { console.log('No intro offer configured for this product'); } // Purchase (Google Play applies intro pricing automatically if the user is eligible) const transaction = await NativePurchases.purchaseProduct({ productIdentifier: 'com.example.premium.monthly', planIdentifier: 'monthly-plan', // Base Plan ID from Google Play Console productType: PURCHASE_TYPE.SUBS, }); console.log('Introductory purchase transaction', transaction.transactionId); ``` ## Best Practices [Section titled “Best Practices”](#best-practices) ### Offer Duration [Section titled “Offer Duration”](#offer-duration) * **Free trials**: 3-14 days is optimal for most apps * **Discounted periods**: 1-3 months works well for building habit * **Price discount**: 50-70% off regular price drives conversions ### Marketing [Section titled “Marketing”](#marketing) * Clearly display the intro offer and regular price * Show what happens after the intro period * Make cancellation easy and transparent * Remind users before the intro period ends ### A/B Testing [Section titled “A/B Testing”](#ab-testing) Test different offer structures: * Free trial length * Discount percentage * Discount duration * Single phase vs. multi-phase ## Important Notes [Section titled “Important Notes”](#important-notes) * Only one introductory offer can be active per subscription at a time * Users can only claim an intro offer once per subscription * Intro offers don’t apply to subscription upgrades/downgrades * Changes to intro offers don’t affect existing subscribers ## Troubleshooting [Section titled “Troubleshooting”](#troubleshooting) **Intro offer not showing:** * Verify the offer is activated in Play Console * Check user eligibility (may have used offer before) * Ensure app is using latest product information **Wrong users receiving offer:** * Review eligibility settings (new vs. existing customers) * Check if user previously subscribed on different device * Verify Play Store account history **Offer not applying at purchase:** * Confirm product ID matches exactly * Check that offer is still active and not expired * Verify date range settings for the offer ## Next Steps [Section titled “Next Steps”](#next-steps) * [Configure sandbox testing](/docs/plugins/native-purchases/android-sandbox-testing/) to test your offers * Monitor conversion rates in Play Console analytics * Consider creating multiple subscription tiers with different offers # Android Play Store Review Guidelines for IAP > Complete guide to passing Google Play review with in-app purchases and subscriptions, including compliance requirements and best practices. Getting your Android app approved on Google Play requires compliance with Google’s policies, especially for apps with in-app purchases and subscriptions. This guide covers everything you need to pass review successfully. ## Release Path That Works [Section titled “Release Path That Works”](#release-path-that-works) 1. **Build a Signed Android App Bundle** New Google Play apps should be uploaded as an Android App Bundle (`.aab`), not a sideloaded debug APK. Keep your `versionCode` increasing on every upload and store your upload key safely if you use Play App Signing. ![Android App Bundle flow](/native-build-assets/android-studio-select-android-app-bundle.webp) 2. **Create the App Record in Play Console** If you do not have a developer account yet, start with [Play Console signup](https://play.google.com/console/signup). Then, in **Home > Create app**, choose the language, app/game type, free/paid status, support email, and accept the required declarations. Choose the free/paid setting carefully. Google lets you change a paid app to free later, but once an app has been offered for free, it cannot be switched to paid. ![Create app in Play Console](/native-build-assets/google-play-console-create-app.webp) 3. **Complete App Content and Store Listing** Before production review, finish the required Play Console declarations: * Privacy policy * Ads * App access * Target audience and content * Content rating * Data Safety * Sensitive permissions declarations, if applicable 4. **Run a Play-Installed Test Track** Start with **internal testing** for fast QA. If your developer account is a personal account created after November 13, 2023, you must also complete a **closed test** with at least 12 opted-in testers for 14 consecutive days before production access. ![Internal testing in Play Console](/native-build-assets/google-play-console-internal-testing.webp) 5. **Verify Billing End-to-End** Install the app from Google Play, not from a locally exported APK. Then confirm that: * Products load from Play correctly * The purchase sheet shows a **test purchase** banner for license testers * Entitlements unlock after purchase * Restore and subscription management flows work ## Google Play Billing Requirements [Section titled “Google Play Billing Requirements”](#google-play-billing-requirements) ### Mandatory Billing System [Section titled “Mandatory Billing System”](#mandatory-billing-system) For digital goods and services, you **must** use Google Play’s billing system: **Digital Goods (Must Use Play Billing):** * Subscriptions to premium features * In-app currency or credits * Digital content (ebooks, music, videos) * Game upgrades and power-ups * App unlocks and premium tiers **Physical Goods (Cannot Use Play Billing):** * Physical merchandise * Real-world services * One-time donations to nonprofits :::note Subscription Setup In Play Console, configure Android subscriptions using the current **subscription -> base plan -> offer** model. In `native-purchases`, pass the Base Plan ID with `planIdentifier`. ::: ### Implementation with Native Purchases [Section titled “Implementation with Native Purchases”](#implementation-with-native-purchases) ```typescript import { NativePurchases, PURCHASE_TYPE } from '@capgo/native-purchases'; // Ensure billing is available on the device const { isBillingSupported } = await NativePurchases.isBillingSupported(); if (!isBillingSupported) throw new Error('Google Play Billing not available'); // Fetch subscription products (Store data is required—never hardcode pricing) const { products } = await NativePurchases.getProducts({ productIdentifiers: ['premium_monthly', 'premium_yearly'], productType: PURCHASE_TYPE.SUBS, }); // Plan identifiers are the Base Plan IDs you create in Google Play Console const transaction = await NativePurchases.purchaseProduct({ productIdentifier: 'premium_monthly', planIdentifier: 'monthly-plan', // REQUIRED on Android, ignored on iOS productType: PURCHASE_TYPE.SUBS, }); console.log('Purchase token for server validation:', transaction.purchaseToken); ``` ## Transparency and Disclosure Requirements [Section titled “Transparency and Disclosure Requirements”](#transparency-and-disclosure-requirements) ### Upfront Pricing Disclosure [Section titled “Upfront Pricing Disclosure”](#upfront-pricing-disclosure) Google Play mandates clear disclosure of all costs before purchase: **Required Elements:** * Exact price in user’s local currency * Billing frequency (monthly, yearly, etc.) * What’s included in the subscription * Total cost for introductory offers * When charges will occur ![UI Design Best Practices](/native-purchases/review-guides/ui-design-dos-donts.webp) **Example of Compliant UI:** ```typescript function SubscriptionCard({ product }) { return ( <div className="subscription-card"> <h3>{product.title}</h3> {/* Show intro offer if available */} {product.introductoryPrice && ( <div className="intro-offer"> <p className="intro-price">{product.introductoryPriceString}</p> <p className="intro-period"> for {product.introductoryPricePeriod} </p> </div> )} {/* Regular price */} <div className="regular-price"> <p className="price">{product.priceString}</p> <p className="period">per {product.subscriptionPeriod}</p> </div> {/* Clear description */} <p>{product.description}</p> {/* Renewal terms */} <p className="terms"> Renews automatically. Cancel anytime in Google Play. </p> <button onClick={() => handlePurchase(product)}> Subscribe Now </button> </div> ); } ``` ### Auto-Renewal Disclosure [Section titled “Auto-Renewal Disclosure”](#auto-renewal-disclosure) Before a subscription auto-renews, Google requires: * Clear notification that renewal will occur * Reminder of the price * Easy access to cancellation Tip The native-purchases plugin works with Google Play to handle auto-renewal notifications automatically. Ensure your subscription products are properly configured in Google Play Console. ### Cross-Platform Pricing Clarity [Section titled “Cross-Platform Pricing Clarity”](#cross-platform-pricing-clarity) If you sell the same entitlement on multiple platforms, keep the product naming, billing period, included benefits, and renewal language aligned so users are not surprised. Prices can legitimately differ because of taxes, local currency, or store economics, but the purchase UI must never hide those differences or imply a different renewal cost than the one Google Play will charge. ## Privacy Policy Requirements [Section titled “Privacy Policy Requirements”](#privacy-policy-requirements) ### Mandatory Privacy Policy [Section titled “Mandatory Privacy Policy”](#mandatory-privacy-policy) If your app includes in-app purchases, you must: 1. **Link in Play Store Listing** * Add privacy policy URL in Play Console * Must be publicly accessible * Must be in the same language as your app 2. **Link Within App** * Display privacy policy in app settings * Show before collecting any user data * Make easily discoverable **Example Implementation:** ```typescript function SettingsScreen() { const openPrivacyPolicy = () => { window.open('https://yourapp.com/privacy', '_blank'); }; const openTerms = () => { window.open('https://yourapp.com/terms', '_blank'); }; return ( <div> <h2>Settings</h2> <button onClick={openPrivacyPolicy}> Privacy Policy </button> <button onClick={openTerms}> Terms of Service </button> <button onClick={() => NativePurchases.manageSubscriptions()}> Manage Subscriptions </button> </div> ); } ``` ### Data Safety Section [Section titled “Data Safety Section”](#data-safety-section) Google Play requires detailed disclosure in the Data Safety section: **For IAP Apps, Declare:** * Purchase history collection * Email addresses (for receipts) * Device IDs (for fraud prevention) * Payment information handling * Analytics data collection The Data Safety section is legally binding. Inaccurate declarations can result in app removal. ## App Content Declarations [Section titled “App Content Declarations”](#app-content-declarations) Google Play review is not only about the binary. Before a production release, complete the declarations on **Policy and programs > App content**. **The minimum set to review carefully:** * **Privacy policy**: Public URL in Play Console, plus an in-app entry point when required * **Ads**: Declare whether the app contains ads * **App access**: Give reviewers working credentials or a clear test path if any screen is gated * **Target audience and content**: Match the real audience of the app * **Content ratings**: Complete the IARC questionnaire so the app is not marked unrated * **Data Safety**: Declare collection, sharing, and security practices accurately Tip If a reviewer needs login credentials, 2FA steps, a region toggle, or a specific test account to access billing, put that in **App access** and in your release notes. Missing reviewer access is a common preventable rejection. ## Common Rejection Reasons [Section titled “Common Rejection Reasons”](#common-rejection-reasons) ### 1. Missing or Incorrect Billing Implementation [Section titled “1. Missing or Incorrect Billing Implementation”](#1-missing-or-incorrect-billing-implementation) **Why It Fails:** * Not using Google Play Billing for digital goods * Using deprecated billing APIs * Implementing custom payment solutions for subscriptions **Prevention:** ```typescript // ✅ Correct: Use native-purchases (uses Google Play Billing) await NativePurchases.purchaseProduct({ productIdentifier: 'premium_monthly', planIdentifier: 'monthly-plan', productType: PURCHASE_TYPE.SUBS, }); // ❌ Wrong: Custom payment processor for subscriptions // await CustomPayment.charge(user, 9.99); ``` ### 2. Unclear Pricing or Hidden Costs [Section titled “2. Unclear Pricing or Hidden Costs”](#2-unclear-pricing-or-hidden-costs) **Why It Fails:** * Price only shown after clicking purchase * Additional fees not disclosed upfront * Vague subscription terms **Prevention:** ```typescript function PurchaseScreen({ product }) { return ( <div> {/* Show ALL costs upfront */} <h2>Premium Subscription</h2> <div className="pricing"> <p className="price">{product.priceString}/month</p> <p className="taxes">Taxes may apply based on location</p> </div> <div className="features"> <h3>Includes:</h3> <ul> <li>Ad-free experience</li> <li>Unlimited cloud storage</li> <li>Priority support</li> </ul> </div> <div className="terms"> <p> Subscription renews automatically unless cancelled at least 24 hours before the end of the current period. </p> <p> Manage or cancel in Google Play Subscriptions. </p> </div> <button onClick={handlePurchase}> Start Subscription </button> </div> ); } ``` ### 3. Deceptive Subscription Patterns [Section titled “3. Deceptive Subscription Patterns”](#3-deceptive-subscription-patterns) **Why It Fails:** * Pre-selecting premium options * Hiding cheaper alternatives * Making cancellation difficult * Fake urgency (“Only 3 spots left!”) ![Description Best Practices](/native-purchases/review-guides/description-guidelines-1.webp) ![Marketing Guidelines](/native-purchases/review-guides/description-guidelines-2.webp) **Prevention:** * Display all subscription tiers equally * Make cancellation clear and accessible * Avoid countdown timers or fake scarcity * Don’t use dark patterns to push expensive options ### 4. Incomplete Testing [Section titled “4. Incomplete Testing”](#4-incomplete-testing) **Why It Fails:** * App crashes when purchasing * Products don’t load * Purchase confirmation doesn’t show * Premium features don’t unlock after purchase * Testing only happened on sideloaded builds instead of a Play-installed testing track **Prevention:** ```typescript import { NativePurchases, PURCHASE_TYPE } from '@capgo/native-purchases'; // Comprehensive testing before submission async function testPurchaseFlow() { try { // 1. Test product loading const { products } = await NativePurchases.getProducts({ productIdentifiers: ['premium_monthly', 'premium_yearly'], productType: PURCHASE_TYPE.SUBS, }); console.log('✓ Products loaded:', products.length); // 2. Test purchase flow const transaction = await NativePurchases.purchaseProduct({ productIdentifier: 'premium_monthly', planIdentifier: 'monthly-plan', productType: PURCHASE_TYPE.SUBS, }); console.log('✓ Purchase completed', transaction.transactionId); // 3. Verify entitlements const { purchases } = await NativePurchases.getPurchases({ productType: PURCHASE_TYPE.SUBS, }); if ( purchases.some( (purchase) => purchase.productIdentifier === 'premium_monthly' && ['PURCHASED', '1'].includes(purchase.purchaseState ?? '') && purchase.isAcknowledged, ) ) { console.log('✓ Premium features unlocked'); } // 4. Test restore await NativePurchases.restorePurchases(); console.log('✓ Restore works'); } catch (error) { console.error('✗ Test failed:', error); } } ``` ### 5. Privacy Policy Violations [Section titled “5. Privacy Policy Violations”](#5-privacy-policy-violations) **Why It Fails:** * No privacy policy link in app * Privacy policy not accessible * Data collection not disclosed * Data Safety section inaccurate **Prevention:** * Add privacy policy to Play Store listing * Include link in app settings * Accurately fill out Data Safety section * Update policy when adding new data collection ## Alternative Billing Programs [Section titled “Alternative Billing Programs”](#alternative-billing-programs) Google’s alternative billing programs are region-specific and can change. If you want anything other than standard Google Play Billing, confirm the exact market eligibility, required APIs, and disclosure language in Play Console immediately before implementation. Note For most apps, sticking to standard Google Play Billing is the simplest and lowest-risk path for review. ## Subscription Management [Section titled “Subscription Management”](#subscription-management) ### Easy Cancellation [Section titled “Easy Cancellation”](#easy-cancellation) Users must be able to: * View active subscriptions easily * Cancel without contacting support * Understand when cancellation takes effect **Implementation:** ```typescript import { NativePurchases } from '@capgo/native-purchases'; function ManageSubscriptionButton() { const openManagement = async () => { try { // Opens Google Play subscription management await NativePurchases.manageSubscriptions(); } catch (error) { // Fallback to direct URL const playStoreUrl = 'https://play.google.com/store/account/subscriptions'; window.open(playStoreUrl, '_blank'); } }; return ( <button onClick={openManagement}> Manage Subscription in Google Play </button> ); } ``` ### Cancellation Grace Period [Section titled “Cancellation Grace Period”](#cancellation-grace-period) **Required Disclosure:** * When does cancellation take effect? * Do users keep access until period ends? * Are partial refunds available? ```typescript function CancellationInfo() { return ( <div className="cancellation-info"> <h3>Cancellation Policy</h3> <ul> <li>Cancel anytime in Google Play</li> <li>Access continues until end of billing period</li> <li>No refunds for partial periods</li> <li>Resubscribe anytime to regain access</li> </ul> <button onClick={() => NativePurchases.manageSubscriptions()}> Manage in Google Play </button> </div> ); } ``` ## Pre-Submission Checklist [Section titled “Pre-Submission Checklist”](#pre-submission-checklist) ![Pre-Submission Checklist](/native-purchases/review-guides/pre-submission-checklist.webp) 1. **Verify Billing Implementation** * Using Google Play Billing (via native-purchases) * All subscription products created in Play Console * Base plans and offers configured correctly * Products are activated and published * Pricing set for all target countries 2. **Test Purchase Flows** * Create license test account * Install the build from a Play testing track * Test each subscription tier * Verify products load correctly * Test purchase completion * Confirm the **test purchase** banner appears * Verify premium features unlock * Test subscription restoration * Test on multiple devices 3. **Review All Copy** * Pricing displayed clearly before purchase * All fees disclosed upfront * Subscription terms are clear * Cancellation process explained * No misleading claims 4. **App Content and Privacy** * Privacy policy linked in Play Console * Privacy policy accessible in app * Ads declaration completed * App access instructions added if the app is gated * Data Safety section completed accurately * Permissions justified and documented 5. **Content Rating and Audience** * Complete content rating questionnaire * Complete target audience and content section * Ensure rating matches actual content * Declare in-app purchases in questionnaire 6. **Prepare Store Listing** * App description accurate * Short description is within 80 characters * Full description is within 4000 characters * At least 2 phone screenshots uploaded * 1024x500 feature graphic uploaded * Screenshots show current version * All required assets uploaded ## Review Timeline [Section titled “Review Timeline”](#review-timeline) **Production Access for New Personal Accounts:** Usually 7 days or less after you apply **First Production Review:** Often several days, sometimes longer if billing or policy questions are raised **Updates:** Often faster than a first release, but still reviewed **Appeals:** Plan for several days and provide exact fixes and reviewer instructions :::tip Rolling Reviews Unlike Apple, Google reviews apps continuously. Your app may go live at any time during the review period, not at a fixed time. ::: ## Testing Before Submission [Section titled “Testing Before Submission”](#testing-before-submission) ### License Testing [Section titled “License Testing”](#license-testing) 1. **Add Test Account:** * Go to Play Console * Settings > License testing * Add Gmail account for testing 2. **Test in Sandbox:** ```typescript import { NativePurchases, PURCHASE_TYPE } from '@capgo/native-purchases'; // Test purchases with license test account async function testInSandbox() { const { isBillingSupported } = await NativePurchases.isBillingSupported(); if (!isBillingSupported) { console.error('Billing not supported in this environment'); return; } // Fetch products (returns test pricing when using a license tester) const { products } = await NativePurchases.getProducts({ productIdentifiers: ['premium_monthly'], productType: PURCHASE_TYPE.SUBS, }); console.log('Test products:', products); // Make test purchase (no charge) const transaction = await NativePurchases.purchaseProduct({ productIdentifier: 'premium_monthly', planIdentifier: 'monthly-plan', productType: PURCHASE_TYPE.SUBS, }); console.log('Test purchase complete:', transaction.transactionId); } ``` 3. **Verify Test Banner:** * When purchasing with test account * Should see “Test purchase” notification * No real charges occur ### Internal and Closed Testing Tracks [Section titled “Internal and Closed Testing Tracks”](#internal-and-closed-testing-tracks) Before production release: 1. Create an **internal testing** track for fast QA or a **closed testing** track for broader testing 2. Upload a signed `.aab` and publish the testing release 3. Add tester email addresses and share the opt-in link 4. Have testers install the build from Google Play 5. Verify purchase flows work end-to-end on the Play-installed build 6. If your personal developer account was created after November 13, 2023, keep at least 12 testers opted in to a closed test for 14 consecutive days before applying for production A sideloaded debug build is not a substitute for a Play-installed testing build when validating Google Play Billing. ## Best Practices for Native Purchases [Section titled “Best Practices for Native Purchases”](#best-practices-for-native-purchases) ### Handle All Purchase States [Section titled “Handle All Purchase States”](#handle-all-purchase-states) ```typescript import { NativePurchases, PURCHASE_TYPE } from '@capgo/native-purchases'; async function handlePurchase(productId: string, planIdentifier?: string) { try { setLoading(true); const transaction = await NativePurchases.purchaseProduct({ productIdentifier: productId, planIdentifier, productType: planIdentifier ? PURCHASE_TYPE.SUBS : PURCHASE_TYPE.INAPP, }); console.log('Purchase token:', transaction.purchaseToken ?? transaction.receipt); // Success - check entitlements from the store const { purchases } = await NativePurchases.getPurchases({ productType: planIdentifier ? PURCHASE_TYPE.SUBS : PURCHASE_TYPE.INAPP, }); const isOwned = purchases.some( (purchase) => purchase.productIdentifier === productId && (purchase.purchaseState === 'PURCHASED' || purchase.purchaseState === '1') && purchase.isAcknowledged, ); if (isOwned) { unlockPremiumFeatures(); showSuccess('Premium activated!'); } } catch (error: any) { // Handle specific error cases switch (error.code) { case 'USER_CANCELLED': // User backed out - no error needed console.log('Purchase cancelled'); break; case 'ITEM_ALREADY_OWNED': // They already own it - restore instead showInfo('You already own this! Restoring...'); await NativePurchases.restorePurchases(); break; case 'ITEM_UNAVAILABLE': showError('This subscription is currently unavailable. Please try again later.'); break; case 'NETWORK_ERROR': showError('Network error. Please check your connection and try again.'); break; default: showError('Purchase failed. Please try again.'); console.error('Purchase error:', error); } } finally { setLoading(false); } } ``` ### Implement Restore Purchases [Section titled “Implement Restore Purchases”](#implement-restore-purchases) ```typescript import { NativePurchases, PURCHASE_TYPE } from '@capgo/native-purchases'; function RestorePurchasesButton() { const [loading, setLoading] = useState(false); const handleRestore = async () => { setLoading(true); try { await NativePurchases.restorePurchases(); const { purchases } = await NativePurchases.getPurchases({ productType: PURCHASE_TYPE.SUBS, }); const hasSubscription = purchases.some( (purchase) => purchase.productType === 'subs' && purchase.isAcknowledged, ); if (hasSubscription) { unlockPremiumFeatures(); showSuccess('Subscriptions restored!'); return; } // Check one-time unlocks if needed const { purchases: iaps } = await NativePurchases.getPurchases({ productType: PURCHASE_TYPE.INAPP, }); const hasInApp = iaps.some((purchase) => purchase.productIdentifier === 'premium_unlock'); if (hasInApp) { unlockPremiumFeatures(); showSuccess('Previous purchases restored!'); return; } showInfo('No previous purchases found.'); } catch (error) { showError('Failed to restore purchases. Please try again.'); } finally { setLoading(false); } }; return ( <button onClick={handleRestore} disabled={loading}> {loading ? 'Restoring...' : 'Restore Purchases'} </button> ); } ``` ### Check Subscription Status [Section titled “Check Subscription Status”](#check-subscription-status) ```typescript import { NativePurchases, PURCHASE_TYPE } from '@capgo/native-purchases'; async function checkSubscriptionStatus() { try { const { purchases } = await NativePurchases.getPurchases({ productType: PURCHASE_TYPE.SUBS, }); const subscription = purchases.find( (purchase) => purchase.productIdentifier === 'premium_monthly' && (purchase.purchaseState === 'PURCHASED' || purchase.purchaseState === '1') && purchase.isAcknowledged, ); if (!subscription) { showPaywall(); return; } console.log('Subscription active:', { productId: subscription.productIdentifier, expiresAt: subscription.expirationDate, willRenew: subscription.willCancel === false, purchaseToken: subscription.purchaseToken, }); unlockPremiumFeatures(); } catch (error) { console.error('Failed to check subscription:', error); } } ``` ## If Your App Gets Rejected [Section titled “If Your App Gets Rejected”](#if-your-app-gets-rejected) ### Common Policy Violations [Section titled “Common Policy Violations”](#common-policy-violations) **Payments Policy:** * Not using Google Play Billing * Misleading subscription terms * Hidden costs **User Data Policy:** * Missing privacy policy * Inaccurate Data Safety declarations * Excessive permissions ### Resolution Steps [Section titled “Resolution Steps”](#resolution-steps) 1. **Review the Violation Notice** * Read the specific policy cited * Understand what Google flagged * Check examples they provided 2. **Fix the Issue** * Address root cause, not just symptoms * Test thoroughly after fix * Document all changes made 3. **Submit Appeal (if applicable)** ![Clarification and Appeal Process](/native-purchases/review-guides/clarification-process.webp) ```plaintext Subject: Policy Violation Appeal - [App Name] Dear Google Play Review Team, I have received notification that my app violates [Policy X.Y]. I have made the following changes to comply: 1. [Specific change made] 2. [Specific change made] 3. [Specific change made] The updated version [version number] addresses all concerns raised. Test account for verification: Email: test@example.com Password: TestPass123 Thank you for your consideration. ``` ![Request Documentation Example](/native-purchases/review-guides/request-documents.webp) 4. **Resubmit or Update** * Upload fixed version * Resubmit for review * Monitor status in Play Console ## Additional Resources [Section titled “Additional Resources”](#additional-resources) * [Google Play Developer Policy Center](https://play.google.com/about/developer-content-policy/) * [Google Play Billing Documentation](https://developer.android.com/google/play/billing) * [Subscriptions Best Practices](https://developer.android.com/google/play/billing/subscriptions) * [Prepare Your App for Review](https://support.google.com/googleplay/android-developer/answer/9859455) * [Testing Requirements for New Personal Accounts](https://support.google.com/googleplay/android-developer/answer/14151465) * [Play Console Help](https://support.google.com/googleplay/android-developer/) ## Need Expert Help? [Section titled “Need Expert Help?”](#need-expert-help) Navigating Play Store review can be complex, especially when you need to combine billing compliance, App content declarations, and testing-track setup. If you need personalized assistance: **[Book a consultation call with our team](https://cal.com/team/capgo/capacitor-consulting-services)** for help with: * Complete Play Store review preparation * Testing track setup and tester recruitment * IAP implementation review * Data Safety and privacy compliance * Rejection troubleshooting and appeals * Complete app submission process Our experts have guided hundreds of apps through successful Play Store submissions and can help you navigate the current requirements. ## Support [Section titled “Support”](#support) Need help with implementation? * Review the [Native Purchases documentation](/docs/plugins/native-purchases/getting-started/) * Check [Android sandbox testing guide](/docs/plugins/native-purchases/android-sandbox-testing/) * Visit [Google Play Developer Support](https://support.google.com/googleplay/android-developer/) # Configure Android Sandbox Testing > Learn how to set up sandbox testing for in-app purchases on Android using Google Play Console. Testing in-app purchases requires proper configuration in Google Play Console. This guide will walk you through setting up sandbox testing for your Android app. ## Use the right build for the job [Section titled “Use the right build for the job”](#use-the-right-build-for-the-job) Before you start, separate these three Android build types: * **Local debug/dev build**: Good for checking UI and native integrations on your device. * **Signed release AAB uploaded to Play Console**: Required for realistic Google Play billing tests. * **Play-installed testing build**: The build your testers install from an internal or closed track. Use this for purchase QA. If you only sideload an APK from Android Studio or `adb`, Google Play Billing may not behave the same way it does in production. For subscription and in-app purchase validation, always test with a build installed from Google Play. ## Prerequisites [Section titled “Prerequisites”](#prerequisites) * A Google Play Console developer account. If you have not created one yet, start at [Play Console signup](https://play.google.com/console/signup). * An app record created in Play Console with your final Android package name * Your in-app products or subscriptions created in Play Console * A test Gmail account that you can add to license testing * A signed release build ready for upload Before you spend time on billing setup, create the app in Play Console and decide whether it will be **free** or **paid**. Google lets you move a paid app to free later, but once an app has been offered for free, it cannot be switched to paid. Use an Android App Bundle (`.aab`) for new Play Store apps: ```bash bunx cap sync android cd android ./gradlew bundleRelease ``` Make sure your Android release signing is already configured before you run `bundleRelease`. If your keystore, signing config, or release passwords are not set yet, create the signed bundle from Android Studio with **Build > Generate Signed App Bundle / APK**, which prompts you for those values. ## Setup Process [Section titled “Setup Process”](#setup-process) 1. **Add Testing Account** In Play Console, open **Settings > License testing** and add the primary Google account used on your Android test device. This ensures purchases show the Play sandbox flow instead of attempting a real charge. ![Add testing account](/native-purchases/android/sandbox-testing/add-testing-account.webp) 2. **Choose a Testing Track** Go to **Test and release > Testing** and choose one of these tracks: * **Internal testing**: Fastest path for QA and billing smoke tests. New bundles are normally available within minutes. * **Closed testing**: Better for broader testing, and required before production for personal developer accounts created after November 13, 2023. For a first release, Play may show a temporary app name and listing information to internal testers for up to 48 hours. ![Create testing track](/native-purchases/android/sandbox-testing/create-testing-track.webp) 3. **Create Tester List** After opening your track, create a tester list and add the Google accounts that should receive the build. If you are working toward production access on a newly created personal account, make sure you use **closed testing** and keep at least 12 testers opted in for 14 consecutive days. ![Create tester list](/native-purchases/android/sandbox-testing/create-tester-list.webp) 4. **Upload a Signed Release Build** Create a new release in the selected testing track and upload your signed `.aab`. New Google Play apps should use an Android App Bundle rather than an APK. After upload, save the release, fix any policy or store listing blockers Play flags, then publish the release to the testing track. ![Upload release build](/native-purchases/android/sandbox-testing/upload-signed-apk.webp) 5. **Join the Testing Program** Open the opt-in URL from your test device and click the **“Become a tester”** button to enroll. Install the app from the Play Store listing created by that opt-in flow, not from a locally exported APK. ![Join testing](/native-purchases/android/sandbox-testing/join-testing-program.webp) 6. **Build and Test** Launch the Play-installed build on the test device and attempt a purchase. You should see a message like: > “This is a test order; you will not be charged.” ![Test purchase](/native-purchases/android/sandbox-testing/test-purchase-confirmation.webp) ## Important Notes [Section titled “Important Notes”](#important-notes) * For billing QA, uninstall any sideloaded copy of the app before installing the Play testing build. * Internal testing is great for fast smoke tests, but closed testing is the track that matters for new personal-account production access. * Test accounts will not be charged for purchases * Test purchases use the same flow as production purchases * You can test all subscription features including trials and introductory offers * Test subscriptions have accelerated renewal periods for faster testing * Use the same Google account for all three places: the Play Store on the device, the tester opt-in flow, and License testing ## Troubleshooting [Section titled “Troubleshooting”](#troubleshooting) **Products not showing in test mode:** * Ensure your app is uploaded to a testing track * Verify the test account is added to License testing * Check that products are active in Google Play Console * Confirm the build was installed from Google Play, not sideloaded locally **“Item not available” error:** * Wait 2-3 hours after creating products for them to become available * Ensure your app’s package name matches the one in Play Console * Verify you’re signed in with a test account * Confirm you uploaded the signed release build that points at the same package name and product catalog **Test purchases showing as real charges:** * Double-check the account is added to License testing * Ensure you’re using the build from the testing track * Verify the testing banner appears during purchase ## Additional Resources [Section titled “Additional Resources”](#additional-resources) * [Test purchases with Google Play Billing](https://developer.android.com/google/play/billing/test) * [Set up an open, closed, or internal test](https://support.google.com/googleplay/android-developer/answer/9845334) * [Testing requirements for new personal developer accounts](https://support.google.com/googleplay/android-developer/answer/14151465) # Getting Started > Learn how to install and use the @capgo/native-purchases plugin to implement one-time purchases and subscriptions with StoreKit 2 and Google Play Billing 7. 1. **Install the package** ```sh bun add @capgo/native-purchases ``` 2. **Sync with native projects** ```sh bunx cap sync ``` 3. **Check billing support** ```typescript import { NativePurchases } from '@capgo/native-purchases'; const { isBillingSupported } = await NativePurchases.isBillingSupported(); if (!isBillingSupported) { throw new Error('Billing is not available on this device'); } ``` 4. **Load products directly from the stores** ```typescript import { NativePurchases, PURCHASE_TYPE } from '@capgo/native-purchases'; const { products } = await NativePurchases.getProducts({ productIdentifiers: [ 'com.example.premium.monthly', 'com.example.premium.yearly', 'com.example.one_time_unlock' ], productType: PURCHASE_TYPE.SUBS, // Use PURCHASE_TYPE.INAPP for one‑time products }); products.forEach((product) => { console.log(product.title, product.priceString); }); ``` 5. **Implement purchase & restore flows** ```typescript import { NativePurchases, PURCHASE_TYPE } from '@capgo/native-purchases'; const monthlyPlanId = 'monthly-plan'; // Base Plan ID from Google Play Console const transaction = await NativePurchases.purchaseProduct({ productIdentifier: 'com.example.premium.monthly', planIdentifier: monthlyPlanId, // REQUIRED for Android subscriptions, ignored on iOS productType: PURCHASE_TYPE.SUBS, quantity: 1, }); console.log('Transaction ID', transaction.transactionId); await NativePurchases.restorePurchases(); ``` * iOS * Create in-app products and subscriptions in App Store Connect. * Use StoreKit Local Testing or Sandbox testers for QA. * No manifest edits required. Make sure your products are approved. * Android * Create in-app products and subscriptions in Google Play Console. * Upload at least an internal test build and add license testers. * Add the billing permission to `AndroidManifest.xml`: ```xml <uses-permission android:name="com.android.vending.BILLING" /> ``` ## Purchase service example [Section titled “Purchase service example”](#purchase-service-example) ```typescript import { NativePurchases, PURCHASE_TYPE, Transaction } from '@capgo/native-purchases'; import { Capacitor } from '@capacitor/core'; class PurchaseService { private premiumProduct = 'com.example.premium.unlock'; private monthlySubId = 'com.example.premium.monthly'; private monthlyPlanId = 'monthly-plan'; // Base Plan ID (Android only) async initialize() { const { isBillingSupported } = await NativePurchases.isBillingSupported(); if (!isBillingSupported) throw new Error('Billing unavailable'); const { products } = await NativePurchases.getProducts({ productIdentifiers: [this.premiumProduct, this.monthlySubId], productType: PURCHASE_TYPE.SUBS, }); console.log('Loaded products', products); if (Capacitor.getPlatform() === 'ios') { NativePurchases.addListener('transactionUpdated', (transaction) => { this.handleTransaction(transaction); }); } } async buyPremium(appAccountToken?: string) { const transaction = await NativePurchases.purchaseProduct({ productIdentifier: this.premiumProduct, productType: PURCHASE_TYPE.INAPP, appAccountToken, }); await this.processTransaction(transaction); } async buyMonthly(appAccountToken?: string) { const transaction = await NativePurchases.purchaseProduct({ productIdentifier: this.monthlySubId, planIdentifier: this.monthlyPlanId, // REQUIRED for Android subscriptions productType: PURCHASE_TYPE.SUBS, appAccountToken, }); await this.processTransaction(transaction); } async restore() { await NativePurchases.restorePurchases(); await this.refreshEntitlements(); } async openManageSubscriptions() { await NativePurchases.manageSubscriptions(); } private async processTransaction(transaction: Transaction) { this.unlockContent(transaction.productIdentifier); this.validateOnServer(transaction).catch(console.error); } private unlockContent(productIdentifier: string) { // persist entitlement locally console.log('Unlocked', productIdentifier); } private async refreshEntitlements() { const { purchases } = await NativePurchases.getPurchases({ productType: PURCHASE_TYPE.SUBS, }); console.log('Current purchases', purchases); } private async handleTransaction(transaction: Transaction) { console.log('StoreKit transaction update:', transaction); await this.processTransaction(transaction); } private async validateOnServer(transaction: Transaction) { await fetch('/api/validate-purchase', { method: 'POST', body: JSON.stringify({ transactionId: transaction.transactionId, receipt: transaction.receipt, purchaseToken: transaction.purchaseToken, }), }); } } ``` ## Required purchase options [Section titled “Required purchase options”](#required-purchase-options) | Option | Platform | Description | | ------------------- | --------------------- | -------------------------------------------------------------------------------------------------------------------------------- | | `productIdentifier` | iOS + Android | SKU/Product ID configured in App Store Connect / Google Play Console. | | `productType` | Android only | `PURCHASE_TYPE.INAPP` or `PURCHASE_TYPE.SUBS`. Defaults to `INAPP`. Always set to `SUBS` for subscriptions. | | `planIdentifier` | Android subscriptions | Base Plan ID from Google Play Console. Required for subscriptions, ignored on iOS and in-app purchases. | | `quantity` | iOS | Only for in-app purchases, defaults to `1`. Android always purchases one item. | | `appAccountToken` | iOS + Android | UUID/string linking the purchase to your user. Required to be UUID on iOS; Android accepts any obfuscated string up to 64 chars. | | `isConsumable` | Android | Set to `true` to auto-consume tokens after granting entitlement for consumables. Defaults to `false`. | ## Checking entitlement status [Section titled “Checking entitlement status”](#checking-entitlement-status) Use `getPurchases()` for a cross-platform view of every transaction the stores report: ```typescript import { NativePurchases, PURCHASE_TYPE } from '@capgo/native-purchases'; const { purchases } = await NativePurchases.getPurchases({ productType: PURCHASE_TYPE.SUBS, }); purchases.forEach((purchase) => { if (purchase.isActive && purchase.expirationDate) { console.log('iOS sub active until', purchase.expirationDate); } const isAndroidIapValid = ['PURCHASED', '1'].includes(purchase.purchaseState ?? '') && purchase.isAcknowledged; if (isAndroidIapValid) { console.log('Grant in-app entitlement for', purchase.productIdentifier); } }); ``` ### Platform behavior [Section titled “Platform behavior”](#platform-behavior) * **iOS**: Subscriptions include `isActive`, `expirationDate`, `willCancel`, and StoreKit 2 listener support. In-app purchases require server receipt validation. * **Android**: `isActive`/`expirationDate` are not populated; call the Google Play Developer API with the `purchaseToken` for authoritative status. `purchaseState` must be `PURCHASED` and `isAcknowledged` must be `true`. ## API quick reference [Section titled “API quick reference”](#api-quick-reference) * `isBillingSupported()` – check for StoreKit / Google Play availability. * `getProduct()` / `getProducts()` – fetch price, localized title, description, intro offers. * `purchaseProduct()` – initiate StoreKit 2 or Billing client purchase flow. * `restorePurchases()` – replay historical purchases and sync to current device. * `getPurchases()` – list all iOS transactions or Play Billing purchases. * `manageSubscriptions()` – open the native subscription management UI. * `addListener('transactionUpdated')` – handle pending StoreKit 2 transactions when your app starts (iOS only). ## Best practices [Section titled “Best practices”](#best-practices) 1. **Show store pricing** – Apple requires displaying `product.title` and `product.priceString`; never hardcode. 2. **Use `appAccountToken`** – deterministically generate a UUID (v5) from your user ID to link purchases to accounts. 3. **Validate server-side** – send `receipt` (iOS) / `purchaseToken` (Android) to your backend for verification. 4. **Handle errors gracefully** – check for user cancellations, network failures, and unsupported billing environments. 5. **Test thoroughly** – follow the [iOS sandbox guide](/docs/plugins/native-purchases/ios-sandbox-testing/) and [Android sandbox guide](/docs/plugins/native-purchases/android-sandbox-testing/). 6. **Offer restore & management** – add UI buttons wired to `restorePurchases()` and `manageSubscriptions()`. ## Revenue next steps [Section titled “Revenue next steps”](#revenue-next-steps) After the purchase flow works, use the [Revenue Playbook](/docs/plugins/native-purchases/revenue-playbook/) to plan your first paid funnel: product scope, ASO, pricing, paywall placement, analytics, and churn feedback. ## Troubleshooting [Section titled “Troubleshooting”](#troubleshooting) **Products not loading** * Make sure the bundle ID / application ID matches store configuration. * Confirm the product IDs are active and approved (App Store) or activated (Google Play). * Wait several hours after creating products; store propagation is not instant. **Purchase cancelled or stuck** * Users can cancel mid-flow; wrap calls in `try/catch` and surface friendly error messages. * For Android, ensure test accounts install the app from Play Store (internal track) so Billing works. * Check logcat/Xcode for billing errors when running on device. **Subscription state incorrect** * Use `getPurchases()` to compare store data with your local entitlement cache. * On Android, always query the Google Play Developer API with the `purchaseToken` to obtain expiration dates or refund status. * On iOS, check `isActive`/`expirationDate` and validate receipts to detect refunds or revocations. # iOS App Store Review Guidelines for IAP > Complete guide to passing App Store review with in-app purchases and subscriptions, including common rejection reasons and best practices. Getting your app approved on the App Store requires careful attention to Apple’s guidelines, especially when implementing in-app purchases and subscriptions. This guide covers everything you need to know to pass review on your first submission. ![iOS App Store Review Process](/native-purchases/review-guides/ios-review-hero.webp) ## Before You Submit [Section titled “Before You Submit”](#before-you-submit) ### Finish App Store Connect Setup [Section titled “Finish App Store Connect Setup”](#finish-app-store-connect-setup) Before Apple reviews your purchase flow, make sure the app record itself is complete: * Add a **Privacy Policy URL** in App Store Connect * Add a **Support URL** that leads to real contact information for users * Complete the **age rating** questionnaire so the app is publishable * Add **App Review contact details** and clear reviewer notes * If login is required, provide a **demo account that does not expire during review** Note Apple treats the support site as more than a placeholder link. It should contain real contact details so users can reach you about app issues, feedback, and feature requests. ![App Store listing metadata with policy and support links](/_docs/policy-links.7G8uCyBB.png) ### Prepare Real Screenshots [Section titled “Prepare Real Screenshots”](#prepare-real-screenshots) * Use current screenshots from the actual build under review * For iPhone, `1290 x 2796` (6.7-inch) is the easiest default size * If your app runs on iPad, upload iPad screenshots too * Current accepted large iPad sizes include `2064 x 2752` (13-inch) and `2048 x 2732` (12.9-inch) * Never stretch iPhone screenshots to fake iPad support ### Dry-Run the Reviewer Journey in TestFlight [Section titled “Dry-Run the Reviewer Journey in TestFlight”](#dry-run-the-reviewer-journey-in-testflight) Run the exact path Apple will follow on a real device: * Install the latest build from TestFlight * Sign in with the review account you plan to provide * Reach the paywall without hidden gestures or debug menus * Complete purchase, restore, and manage-subscription flows * Verify the app still behaves correctly if permissions are denied ## In-App Purchase Requirements [Section titled “In-App Purchase Requirements”](#in-app-purchase-requirements) ### Pricing Transparency (Critical) [Section titled “Pricing Transparency (Critical)”](#pricing-transparency-critical) Apple requires crystal-clear pricing disclosure before any purchase: **Must-Have Elements:** * Display exact price before purchase button * Show billing frequency (e.g., “$9.99/month”) * Clearly state what users get for their money * Indicate when charges will occur **Common Rejection:** > “Subscription pricing must be clear and upfront.” :::caution Price Consistency All prices must match across: * App Store metadata listing * In-app purchase screens * Subscription management screens Even a $1 discrepancy between store listing ($4.99) and app ($5.99) will trigger automatic rejection. ::: ### Subscription Plan Presentation [Section titled “Subscription Plan Presentation”](#subscription-plan-presentation) **Required Disclosures:** * All available subscription tiers displayed together * Clear comparison of features per tier * No auto-defaulting to premium tiers through UI tricks * Easy-to-locate cancellation instructions ![UI Design Dos and Don'ts](/native-purchases/review-guides/ui-design-dos-donts.webp) ![Paywall with restore purchases and legal links](/_docs/paywall-links.cIq_wEKi.png) **Example of Compliant UI:** ```typescript import { NativePurchases } from '@capgo/native-purchases'; function SubscriptionScreen() { return ( <div> <h2>Choose Your Plan</h2> {/* Show all tiers equally */} <PlanCard title="Basic" price="$4.99/month" features={['Feature A', 'Feature B']} /> <PlanCard title="Premium" price="$9.99/month" features={['All Basic', 'Feature C', 'Feature D']} highlighted={false} // Don't force premium /> {/* Clear cancellation info */} <Text> Cancel anytime in Settings > Subscriptions. No refunds for partial periods. </Text> </div> ); } ``` ### Restore Purchases [Section titled “Restore Purchases”](#restore-purchases) **Required Implementation:** Every app with IAP must provide a way for users to restore previous purchases without contacting support. ```typescript import { NativePurchases, PURCHASE_TYPE } from '@capgo/native-purchases'; async function restorePurchases() { try { await NativePurchases.restorePurchases(); const { purchases } = await NativePurchases.getPurchases({ productType: PURCHASE_TYPE.SUBS, }); const activeSub = purchases.find( (purchase) => purchase.isActive && purchase.expirationDate, ); if (activeSub) { unlockPremiumFeatures(); showMessage('Purchases restored successfully!'); return; } const { purchases: iaps } = await NativePurchases.getPurchases({ productType: PURCHASE_TYPE.INAPP, }); const hasIap = iaps.some((purchase) => purchase.productIdentifier === 'premium_unlock'); showMessage( hasIap ? 'Premium purchase restored!' : 'No previous purchases found.', ); } catch (error) { showError('Failed to restore purchases. Please try again.'); } } // Add a visible "Restore Purchases" button <Button onClick={restorePurchases}> Restore Purchases </Button> ``` ## Common Rejection Reasons [Section titled “Common Rejection Reasons”](#common-rejection-reasons) ### 1. App Crashes or Broken Functionality [Section titled “1. App Crashes or Broken Functionality”](#1-app-crashes-or-broken-functionality) **Why It Fails:** * App crashes on launch * Purchase flow fails to complete * Features shown in screenshots don’t work **Prevention:** * Test on real devices (not just simulators) * Test all subscription flows end-to-end * Verify receipt validation works * Check network error handling ### 2. Metadata Mismatches [Section titled “2. Metadata Mismatches”](#2-metadata-mismatches) **Why It Fails:** * Screenshots show features not in current build * Description mentions functionality that doesn’t exist * Pricing in metadata differs from in-app pricing ![Metadata Checklist](/native-purchases/review-guides/metadata-checklist.webp) **Prevention:** ```typescript // Document exactly what's in each tier const SUBSCRIPTION_FEATURES = { basic: ['Ad-free', 'Cloud sync', 'Basic themes'], premium: ['Ad-free', 'Cloud sync', 'All themes', 'Priority support'] }; // Use these in both your app AND App Store description ``` ### 3. Missing Permission Explanations [Section titled “3. Missing Permission Explanations”](#3-missing-permission-explanations) **Why It Fails:** * Requesting camera/location/health without explanation * Permission requests buried multiple screens deep * Vague or generic permission descriptions **Prevention:** Update your `Info.plist` with clear explanations: ![Permission copy that is too vague for review](/_docs/rejected-permissions.B718tC7_.webp) ![Permission copy with clearer explanations](/_docs/accepted-permissions.DfOXuL54.png) ```xml <key>NSCameraUsageDescription</key> <string>Camera access is needed to scan product barcodes for quick subscription upgrades.</string> <key>NSLocationWhenInUseUsageDescription</key> <string>Location helps us show relevant local content in your Premium subscription.</string> ``` ### 4. Misleading Marketing [Section titled “4. Misleading Marketing”](#4-misleading-marketing) **Why It Fails:** * Claims like “#1 app in world” without proof * “Unlimited” features that have hidden limits * Fake urgency tactics (“Only 2 spots left!”) ![Description Guidelines Examples](/native-purchases/review-guides/description-guidelines-1.webp) ![Additional Description Guidelines](/native-purchases/review-guides/description-guidelines-2.webp) **Prevention:** * Be specific and factual in descriptions * Avoid superlatives without evidence * Don’t pressure users with fake scarcity ### 5. Hidden Cancellation Process [Section titled “5. Hidden Cancellation Process”](#5-hidden-cancellation-process) **Why It Fails:** * No mention of how to cancel * Cancellation button hidden or obscured * Multi-step cancellation process without Apple’s native flow **Prevention:** ```typescript // Always inform users about cancellation function SubscriptionInfo() { return ( <div> <h3>How to Cancel</h3> <ol> <li>Open iPhone Settings</li> <li>Tap your name at the top</li> <li>Tap Subscriptions</li> <li>Select this app and tap Cancel</li> </ol> <p>Or manage directly in the App Store app.</p> <Button onClick={openSubscriptionManagement}> Manage Subscription in Settings </Button> </div> ); } async function openSubscriptionManagement() { // Direct link to iOS subscription management await NativePurchases.showManageSubscriptions(); } ``` ## Privacy & Data Usage (Section 5.1.1) [Section titled “Privacy & Data Usage (Section 5.1.1)”](#privacy--data-usage-section-511) Apple has significantly tightened privacy requirements in 2025. ### Required Disclosures [Section titled “Required Disclosures”](#required-disclosures) **For Every Permission:** 1. Why you need it (specific use case) 2. When it will be used 3. How data is stored/shared 4. Whether it’s optional or required ### Example: Proper Permission Flow [Section titled “Example: Proper Permission Flow”](#example-proper-permission-flow) ```typescript async function requestCameraPermission() { // Show explanation BEFORE requesting await showDialog({ title: 'Camera Access', message: 'We need camera access to let you scan barcodes for quick product lookup. Your photos are never uploaded or stored.', buttons: ['Not Now', 'Allow'] }); // Then request permission const result = await Camera.requestPermissions(); return result.camera === 'granted'; } ``` ### Privacy Nutrition Labels [Section titled “Privacy Nutrition Labels”](#privacy-nutrition-labels) Ensure your App Store privacy labels accurately reflect: * Purchase history collection * Email addresses (for receipts) * Device IDs (for fraud prevention) * Usage data (for analytics) Inaccurate privacy labels are a common rejection reason in 2025. Audit your data collection carefully. ## Pre-Submission Checklist [Section titled “Pre-Submission Checklist”](#pre-submission-checklist) ![Pre-Submission Checklist](/native-purchases/review-guides/pre-submission-checklist.webp) 1. **Test All Purchase Flows** * Buy each subscription tier * Test free trials * Verify introductory offers apply correctly * Test restore purchases * Verify Family Sharing (if enabled) * Test on multiple devices 2. **Verify Pricing Consistency** * Check App Store metadata matches in-app prices * Verify all currencies are correct * Confirm free trial durations match descriptions * Check introductory offer terms are accurate 3. **Review All Copy** * Remove placeholder text * Verify claims are testable * Check grammar and spelling * Ensure descriptions match current build * Remove competitor mentions 4. **Test Permissions** * Request only necessary permissions * Show clear explanations before requesting * Test “Deny” flows (app should still work) * Verify Info.plist descriptions are clear 5. **Prepare Test Account** * Create a review account that remains valid during review * Document login credentials in App Review information * Verify the reviewer can reach the paywall and complete the purchase flow * Include extra accounts or app-specific switches in the Notes field if needed 6. **Check Metadata** * Screenshots match current UI * Support URL includes real contact information * Privacy policy URL is filled in * Age rating matches the content in the build * App preview video (if any) shows current version * Description accurately describes features * Privacy policy is accessible in-app and from the store listing 7. **Write Detailed Review Notes** ```plaintext Contact: Name: Jane Developer Email: review@yourapp.com Phone: +1 555-0100 Test Account: Email: reviewer@test.com Password: TestPass123! This account does not expire during review. Testing Instructions: 1. Log in with test account above 2. Tap "Upgrade to Premium" button 3. Select "Monthly Premium" subscription 4. Complete purchase (no charge in sandbox) 5. Verify premium features unlock Note: Subscription pricing is clearly shown before purchase. Cancellation instructions are in Settings > Account. ``` ## Review Timeline [Section titled “Review Timeline”](#review-timeline) ![App Store Review Timeline](/native-purchases/review-guides/review-timeline.webp) **Standard Review:** 24-48 hours **Peak Periods:** 3-5 days (App Store holiday releases) **Weekends:** No reviews processed **Expedited Review:** Available for critical bug fixes (request via App Store Connect) Common statuses you will see in App Store Connect: * `Waiting for Review` * `In Review` * `Pending Developer Release` * `Rejected` Tip Submit early in the week to avoid weekend delays. Monday submissions typically get reviewed by Wednesday. ## 2026 Submission Focus [Section titled “2026 Submission Focus”](#2026-submission-focus) ### Current Focus Areas [Section titled “Current Focus Areas”](#current-focus-areas) **1. Subscription Clarity** * Side-by-side plan comparisons required * No “dark patterns” that hide cheaper options * Clear downgrade/upgrade paths **2. Metadata Accuracy** * Screenshots must match the build being reviewed * iPad screenshots are required if iPad support is enabled * Support URL and privacy policy should already be live before submission **3. Privacy and Review Detail Quality** * Privacy disclosures must match what your SDKs actually collect * App Review contact info and notes should be complete on the first submission * Demo credentials must stay valid for the full review window **4. Submission Readiness** * Apple updates minimum SDK requirements regularly, so confirm the current deadline before uploading a release build * TestFlight is the safest place to verify the exact reviewer path before you submit ## Best Practices for Native Purchases Plugin [Section titled “Best Practices for Native Purchases Plugin”](#best-practices-for-native-purchases-plugin) ### Implement Proper Error Handling [Section titled “Implement Proper Error Handling”](#implement-proper-error-handling) ```typescript import { NativePurchases, PURCHASE_TYPE } from '@capgo/native-purchases'; async function handlePurchase(productId: string) { try { const transaction = await NativePurchases.purchaseProduct({ productIdentifier: productId, productType: PURCHASE_TYPE.SUBS, }); // Success await validateReceiptOnServer(transaction.receipt); showSuccess('Subscription activated!'); unlockFeatures(); } catch (error: any) { // Handle specific error cases if (error.code === 'USER_CANCELLED') { // User cancelled - don't show error console.log('Purchase cancelled by user'); } else if (error.code === 'PAYMENT_PENDING') { showInfo('Payment is pending. Please check back later.'); } else if (error.code === 'PRODUCT_ALREADY_PURCHASED') { // Restore instead await NativePurchases.restorePurchases(); } else { // Show user-friendly error showError('Unable to complete purchase. Please try again.'); } } } ``` ### Display Loading States [Section titled “Display Loading States”](#display-loading-states) ```typescript function PurchaseButton({ productId }: { productId: string }) { const [loading, setLoading] = useState(false); const handlePurchase = async () => { setLoading(true); try { await NativePurchases.purchaseProduct({ productIdentifier: productId }); } finally { setLoading(false); } }; return ( <button onClick={handlePurchase} disabled={loading}> {loading ? 'Processing...' : 'Subscribe Now'} </button> ); } ``` ### Show Terms Clearly [Section titled “Show Terms Clearly”](#show-terms-clearly) ```typescript function SubscriptionTerms() { return ( <div className="terms"> <p> Subscription automatically renews unless cancelled at least 24 hours before the end of the current period. </p> <p> Your account will be charged for renewal within 24 hours prior to the end of the current period. </p> <p> Subscriptions may be managed by the user and auto-renewal may be turned off in Account Settings after purchase. </p> <p> <a href="/terms">Terms of Service</a> | <a href="/privacy">Privacy Policy</a> </p> </div> ); } ``` ## If Your App Gets Rejected [Section titled “If Your App Gets Rejected”](#if-your-app-gets-rejected) ### Steps to Resolve [Section titled “Steps to Resolve”](#steps-to-resolve) 1. **Read the rejection carefully** * Note the specific guideline cited (e.g., 3.1.1, 5.1.1) * Understand exactly what Apple flagged 2. **Fix the issue thoroughly** * Don’t just patch - fix root cause * Test the fix extensively * Document what you changed 3. **Respond in Resolution Center** ```plaintext Thank you for your feedback. I have addressed the issue: Issue: Subscription pricing not clear upfront Fix: Added explicit pricing display on subscription selection screen showing "$9.99/month" before purchase button. Also added cancellation instructions on the same screen. The changes are in this submission and can be tested using the provided test account. ``` 4. **Resubmit promptly** * Resubmissions are typically reviewed faster * Usually within 24 hours ### Appeal Process [Section titled “Appeal Process”](#appeal-process) If you believe the rejection is incorrect: ![App Store Clarification Process](/native-purchases/review-guides/clarification-process.webp) 1. Click “Appeal” in App Store Connect 2. Provide clear evidence: * Screenshots showing compliance * References to specific guidelines * Explanation of how you meet requirements 3. Be professional and factual 4. Include test account if functionality is hard to find ![Request for Documents Example](/native-purchases/review-guides/request-documents.webp) ## Additional Resources [Section titled “Additional Resources”](#additional-resources) * [Apple App Store Review Guidelines](https://developer.apple.com/app-store/review/guidelines/) * [In-App Purchase Guidelines](https://developer.apple.com/app-store/review/guidelines/#in-app-purchase) * [Subscriptions Best Practices](https://developer.apple.com/app-store/subscriptions/) * [App Store Connect Help](https://developer.apple.com/help/app-store-connect/) * [Screenshot Specifications](https://developer.apple.com/help/app-store-connect/reference/app-information/screenshot-specifications) * [Platform Version Information](https://developer.apple.com/help/app-store-connect/reference/app-information/platform-version-information) ## Support [Section titled “Support”](#support) If you’re still having issues: * Review the [Native Purchases documentation](/docs/plugins/native-purchases/getting-started/) * Check [common troubleshooting issues](/docs/plugins/native-purchases/getting-started/#troubleshooting) * Contact Apple Developer Support for guideline clarifications ### Need Expert Help? [Section titled “Need Expert Help?”](#need-expert-help) Struggling with app review or need personalized assistance? **[Book a consultation call with our team](https://cal.com/team/capgo/capacitor-consulting-services)** for dedicated support with: * IAP implementation review and optimization * App Store review preparation and strategy * Submission checklist review * Rejection resolution and appeals * Complete testing and validation Our experts have successfully helped hundreds of apps pass review! # Create iOS Auto-Renewable Subscription > Step-by-step guide to creating auto-renewable subscriptions in App Store Connect for the native-purchases plugin. Auto-renewable subscriptions provide recurring access to content, services, or premium features in your iOS app. This guide walks you through creating subscriptions in App Store Connect. ## Overview [Section titled “Overview”](#overview) Auto-renewable subscriptions automatically renew at the end of each billing period until users cancel. They’re perfect for: * Premium content and features * Ad-free experiences * Cloud storage and sync * Streaming services * Professional tools and utilities ## Prerequisites [Section titled “Prerequisites”](#prerequisites) Before creating subscriptions, you must: 1. [Create a subscription group](/docs/plugins/native-purchases/ios-subscription-group/) to organize your subscriptions 2. Have an active Apple Developer Program membership 3. Complete banking and tax information in App Store Connect ## Creating a Subscription [Section titled “Creating a Subscription”](#creating-a-subscription) 1. **Navigate to Subscriptions** In App Store Connect, select your app and go to **Monetize > Subscriptions**. Select your subscription group or create a new one if needed. ![Navigate to subscriptions](/native-purchases/ios/create-subscription/navigate-to-subscriptions.webp) 2. **Create New Subscription** Click the **+** icon next to your subscription group to add a new subscription. 3. **Enter Basic Information** **Reference Name**: Descriptive name for your internal use (not shown to customers) * Examples: “Premium Monthly”, “Ultimate Annual”, “Basic Plan” **Product ID**: Unique identifier for this subscription (cannot be changed later) * Format: `com.yourcompany.yourapp.premium_monthly` * Use descriptive, lowercase names with underscores * Required for configuring the native-purchases plugin ![Enter subscription details](/native-purchases/ios/create-subscription/enter-subscription-info.webp) 4. **Configure Duration** Select the subscription duration from available options: * 1 week * 1 month * 2 months * 3 months * 6 months * 1 year The duration determines how often users are billed. 5. **Set Up Pricing** Click **Add Subscription Price** to configure pricing: **Base Territory**: Select your primary market (usually your country) **Price**: Set the subscription price * Apple automatically converts to other currencies * Choose from Apple’s price tiers * Consider perceived value and market rates ![Configure pricing](/native-purchases/ios/create-subscription/configure-pricing.webp) 6. **Family Sharing (Optional)** Decide whether to enable Family Sharing, which allows up to 6 family members to access the subscription. Caution Once Family Sharing is enabled, it cannot be turned off for this product. **Enable if:** * Content is appropriate for family use * You want to increase value proposition * Your business model supports it **Don’t enable if:** * Subscription is for individual use only * Content is personalized to the user * You want to maximize revenue per user 7. **Add Localizations** Add subscription display information in all languages your app supports: **Subscription Display Name**: Customer-facing name (e.g., “Premium Monthly”) **Description**: Brief description of what the subscription includes * Keep it concise and benefit-focused * Mention key features * Highlight value proposition ![Add localizations](/native-purchases/ios/create-subscription/add-localization.webp) 8. **App Store Promotional Image (Optional)** Upload a promotional image for this subscription (312x390 pixels): * Shows in the App Store subscription page * Should match your app’s design * Include subscription name for clarity Note While images are optional for initial submission, they’re required for promotional display in the App Store. You can add them later. 9. **Save and Submit** Click **Save** to create the subscription. **For First Subscription:** * Must be submitted with a new app version * Include in your next App Store submission * Cannot submit independently **For Subsequent Subscriptions:** * Can be submitted directly from the Subscriptions page * Don’t require a new app version * Available after first subscription is approved ## Subscription Status [Section titled “Subscription Status”](#subscription-status) Your subscription will have one of these statuses: | Status | Description | Can Test? | | ---------------------- | -------------------------- | ------------- | | **Missing Metadata** | Incomplete setup | Yes (sandbox) | | **Ready to Submit** | Complete but not submitted | Yes (sandbox) | | **Waiting for Review** | Submitted to Apple | Yes (sandbox) | | **In Review** | Being reviewed by Apple | Yes (sandbox) | | **Approved** | Available for purchase | Yes | | **Rejected** | Needs changes | Yes (sandbox) | Tip You can test subscriptions in sandbox mode even if they show “Missing Metadata” or “Ready to Submit”! ## Using in Your App [Section titled “Using in Your App”](#using-in-your-app) Once created, reference the subscription in your app using the product ID: ```typescript import { NativePurchases, PURCHASE_TYPE } from '@capgo/native-purchases'; // Fetch subscription products direct from StoreKit const { products } = await NativePurchases.getProducts({ productIdentifiers: [ 'com.yourcompany.yourapp.premium_monthly', 'com.yourcompany.yourapp.premium_annual', ], productType: PURCHASE_TYPE.SUBS, }); products.forEach((product) => { console.log(`${product.title}: ${product.priceString}`); console.log(`Duration: ${product.subscriptionPeriod}`); console.log(`Description: ${product.description}`); }); // Purchase a subscription (StoreKit 2 automatically handles intro pricing and offers) try { const transaction = await NativePurchases.purchaseProduct({ productIdentifier: 'com.yourcompany.yourapp.premium_monthly', productType: PURCHASE_TYPE.SUBS, }); console.log('Transaction ID:', transaction.transactionId); // StoreKit receipts are included on iOS for server-side validation await sendReceiptToBackend(transaction.receipt); } catch (error) { console.error('Purchase failed:', error); } // Check subscription status using the store's data const { purchases } = await NativePurchases.getPurchases({ productType: PURCHASE_TYPE.SUBS, }); const premium = purchases.find( (purchase) => purchase.productIdentifier === 'com.yourcompany.yourapp.premium_monthly', ); if (premium?.isActive) { console.log('Expires:', premium.expirationDate); console.log('Will renew:', premium.willCancel === false); console.log('Store state:', premium.subscriptionState); unlockPremiumFeatures(); } else { showPaywall(); } ``` ## Best Practices [Section titled “Best Practices”](#best-practices) ### Pricing Strategy [Section titled “Pricing Strategy”](#pricing-strategy) * **Monthly plans**: Lower barrier to entry, builds habit * **Annual plans**: Better value, higher LTV, lower churn * **Multiple tiers**: Basic, Premium, Ultimate for different user segments * **Competitive analysis**: Research similar apps’ pricing ### Product IDs [Section titled “Product IDs”](#product-ids) * Use consistent naming: `company.app.tier_duration` * Include tier and duration in ID: `premium_monthly`, `ultimate_annual` * Avoid changing product IDs (they’re permanent) * Document all product IDs for your team ### Family Sharing [Section titled “Family Sharing”](#family-sharing) * Enable for family-oriented apps (games, educational, entertainment) * Consider impact on revenue * Test sharing behavior thoroughly * Communicate sharing capability in marketing ### Localization [Section titled “Localization”](#localization) * Translate all subscription names and descriptions * Consider regional pricing differences * Test display in all supported languages * Use culturally appropriate marketing language ### Promotional Images [Section titled “Promotional Images”](#promotional-images) * Maintain consistent visual style * Include subscription name and key benefit * Update for seasonal promotions * Match app’s overall design language ## Common Subscription Patterns [Section titled “Common Subscription Patterns”](#common-subscription-patterns) ### Single Tier (Freemium) [Section titled “Single Tier (Freemium)”](#single-tier-freemium) ```plaintext Free App + Premium Subscription - Basic: Free (limited features) - Premium Monthly: $4.99 - Premium Annual: $39.99 (save 33%) ``` ### Multi-Tier (Good, Better, Best) [Section titled “Multi-Tier (Good, Better, Best)”](#multi-tier-good-better-best) ```plaintext - Basic Monthly: $4.99 - Premium Monthly: $9.99 - Ultimate Monthly: $19.99 - Basic Annual: $49.99 - Premium Annual: $99.99 - Ultimate Annual: $199.99 ``` ### Consumable + Subscription Hybrid [Section titled “Consumable + Subscription Hybrid”](#consumable--subscription-hybrid) ```plaintext - Credit packs (consumable) - Monthly subscription (unlimited credits) - Annual subscription (unlimited + bonus features) ``` ## Troubleshooting [Section titled “Troubleshooting”](#troubleshooting) **Subscription not loading in app:** * Verify product ID matches exactly (case-sensitive) * Check subscription is in subscription group * Ensure bundle identifier matches App Store Connect * Wait 2-3 hours after creating product **Cannot submit subscription:** * Complete all required fields (name, description, price) * Add at least one localization * Verify banking/tax info is approved * Check if first subscription (requires app version) **Family Sharing toggle disabled:** * Already enabled (cannot be disabled) * Check in subscription details * Contact Apple Support if stuck **Price tier not available:** * May be restricted in some territories * Choose alternative tier * Contact Apple for pricing questions **“Invalid Product ID” error:** * Must be reverse domain format * Cannot contain spaces or special characters * Check for typos * Verify uniqueness across all products ## Next Steps [Section titled “Next Steps”](#next-steps) * [Create an introductory offer](/docs/plugins/native-purchases/ios-introductory-offer/) to attract new subscribers * [Configure sandbox testing](/docs/plugins/native-purchases/ios-sandbox-testing/) to test your subscriptions * Set up promotional offers for win-back and retention * Implement subscription analytics tracking ## Additional Resources [Section titled “Additional Resources”](#additional-resources) For more details, refer to the [official Apple documentation on auto-renewable subscriptions](https://developer.apple.com/documentation/storekit/in-app_purchase/subscriptions_and_offers). # Create iOS Subscription Introductory Offer > Learn how to create introductory offers for auto-renewable subscriptions on iOS to attract and convert new subscribers. Introductory offers allow you to provide eligible users with free trials or discounted introductory pricing to reduce barriers to entry and increase subscription conversions. ## Overview [Section titled “Overview”](#overview) Introductory offers are one of the most effective tools for growing your subscriber base. They allow users to: * Try your premium features risk-free * Experience value before committing * Start at a lower price point * Build confidence in your product ## Offer Types [Section titled “Offer Types”](#offer-types) iOS supports three types of introductory offers: ### 1. Free Trial [Section titled “1. Free Trial”](#1-free-trial) Customers get complimentary access for a specified duration. After the trial, they’re charged at standard rates if they don’t cancel. **Examples:** * 7 days free * 14 days free * 1 month free **Best for:** * High-value subscriptions * Feature-rich apps * Building user habit ### 2. Pay Up Front [Section titled “2. Pay Up Front”](#2-pay-up-front) Customers pay a single discounted price that covers the introductory period. **Examples:** * $1.99 for 2 months (then $9.99/month) * $9.99 for 3 months (then $19.99/month) **Best for:** * Commitment signals * Cash flow needs * Testing price sensitivity ### 3. Pay As You Go [Section titled “3. Pay As You Go”](#3-pay-as-you-go) Customers pay a reduced price for multiple billing cycles. **Examples:** * $1.99/month for 3 months (then $9.99/month) * $4.99/month for 6 months (then $14.99/month) **Best for:** * Gradual commitment * Long-term value demonstration * Reducing perceived risk ## Eligibility Requirements [Section titled “Eligibility Requirements”](#eligibility-requirements) Users can only receive introductory offers if they: * Haven’t previously received an introductory offer for the product * Haven’t received an introductory offer for any product in the same subscription group * Haven’t had an active subscription to the product Note Apple handles eligibility checking automatically. The native-purchases plugin provides methods to check eligibility before presenting offers. ## Prerequisites [Section titled “Prerequisites”](#prerequisites) You must first [create an auto-renewable subscription](/docs/plugins/native-purchases/ios-create-subscription/) before adding an introductory offer. ## Creating an Introductory Offer [Section titled “Creating an Introductory Offer”](#creating-an-introductory-offer) 1. **Navigate to Subscription** In App Store Connect, go to your app’s **Monetize > Subscriptions** section and select the subscription you want to add an offer to. 2. **Add Subscription Price** Click the **+** icon next to “Subscription Prices” to open the pricing modal. 3. **Create Introductory Offer** Select **“Create introductory offer”** from the options. ![Create introductory offer](/native-purchases/ios/introductory-offer/create-introductory-offer.webp) 4. **Configure Countries and Start Date** **Countries and Regions**: Select where the offer will be available * Choose all countries for maximum reach * Or limit to specific markets for testing **Start Date**: When the offer becomes available * Can be immediate or scheduled for the future * Useful for coordinating with marketing campaigns **End Date (Optional)**: When the offer expires * Leave blank for ongoing availability * Set a date for limited-time promotions 5. **Select Offer Type** Choose one of the three offer types: **Free** (Free Trial) * Select duration (days, weeks, months) * Examples: 7 days, 2 weeks, 1 month **Pay Up Front** * Set single payment price * Set duration covered by payment * Example: $1.99 for 2 months **Pay As You Go** * Set discounted price per period * Set number of periods * Example: $2.99/month for 3 months 6. **Review and Confirm** Review the summary showing: * Offer type and duration * Pricing details * Regular price after intro period * Availability dates and countries 7. **Save** Click **Save** to create the introductory offer. It will be available for testing immediately in sandbox mode. ## Offer Configuration Examples [Section titled “Offer Configuration Examples”](#offer-configuration-examples) ### Example 1: Standard Free Trial [Section titled “Example 1: Standard Free Trial”](#example-1-standard-free-trial) ```plaintext Type: Free Duration: 7 days Then: $9.99/month ``` **User Journey:** * Day 1-7: Free access * Day 8: First charge of $9.99 * Monthly charges continue ### Example 2: Upfront Discounted Period [Section titled “Example 2: Upfront Discounted Period”](#example-2-upfront-discounted-period) ```plaintext Type: Pay Up Front Price: $4.99 Duration: 3 months Then: $9.99/month ``` **User Journey:** * Day 1: Charged $4.99 * 90 days access * Day 91: Charged $9.99/month ### Example 3: Gradual Introduction [Section titled “Example 3: Gradual Introduction”](#example-3-gradual-introduction) ```plaintext Type: Pay As You Go Price: $2.99/month Periods: 6 months Then: $9.99/month ``` **User Journey:** * Months 1-6: $2.99/month * Month 7+: $9.99/month ## Using in Your App [Section titled “Using in Your App”](#using-in-your-app) The native-purchases plugin automatically handles introductory offer presentation and eligibility: ```typescript import { NativePurchases, PURCHASE_TYPE } from '@capgo/native-purchases'; // Fetch products with intro offer information const { products } = await NativePurchases.getProducts({ productIdentifiers: ['com.yourapp.premium_monthly'], productType: PURCHASE_TYPE.SUBS, }); const product = products[0]; // Display intro offer details (StoreKit sends localized metadata) if (product.introductoryPrice) { console.log('Intro price:', product.introductoryPriceString); console.log('Intro period:', product.introductoryPricePeriod); console.log('Intro cycles:', product.introductoryPriceCycles); console.log('Regular price:', product.priceString); } else { console.log('No intro offer configured'); } // Purchase (StoreKit automatically applies intro pricing if eligible) try { const transaction = await NativePurchases.purchaseProduct({ productIdentifier: 'com.yourapp.premium_monthly', productType: PURCHASE_TYPE.SUBS, }); console.log('Subscription active, receipt length:', transaction.receipt?.length); await validateReceiptOnServer(transaction.receipt); } catch (error) { console.error('Purchase failed:', error); } ``` ## Displaying Intro Offers to Users [Section titled “Displaying Intro Offers to Users”](#displaying-intro-offers-to-users) ### Best Practices for UI [Section titled “Best Practices for UI”](#best-practices-for-ui) **Clear Value Proposition:** ```plaintext Try Premium Free for 7 Days Then $9.99/month. Cancel anytime. ``` **Emphasize Savings:** ```plaintext Start at Just $1.99 Get 3 months of Premium for only $1.99 Then $9.99/month ``` **Transparent Communication:** ```plaintext Your Free Trial • Access all premium features • No charge for 7 days • $9.99/month after trial • Cancel anytime, even during trial ``` ### Example Implementation [Section titled “Example Implementation”](#example-implementation) ```typescript function formatIntroOffer(product: any): string { if (!product.introductoryPrice) { return `${product.priceString} per ${product.subscriptionPeriod}`; } const intro = product.introductoryPrice; const regular = product.priceString; if (intro.price === 0) { // Free trial return `Try free for ${intro.periodString}, then ${regular}`; } else if (intro.cycles === 1) { // Pay up front return `${intro.priceString} for ${intro.periodString}, then ${regular}`; } else { // Enterprise return `${intro.priceString} for ${intro.cycles} ${intro.periodString}s, then ${regular}`; } } ``` ## Marketing Best Practices [Section titled “Marketing Best Practices”](#marketing-best-practices) ### Trial Length Strategy [Section titled “Trial Length Strategy”](#trial-length-strategy) * **3-7 days**: Quick decision apps, games * **7-14 days**: Standard for most apps * **14-30 days**: Complex tools, professional apps * **30+ days**: High-value B2B or enterprise ### Pricing Psychology [Section titled “Pricing Psychology”](#pricing-psychology) * **$0.99-$1.99**: Very low barrier, good for testing * **50% off**: Strong perceived value * **First month free**: Common, familiar pattern ### Communication Timing [Section titled “Communication Timing”](#communication-timing) * **Before trial ends**: Remind users of upcoming charge * **Highlight value**: Show usage stats, achievements * **Easy cancellation**: Build trust with transparent process ## Testing Intro Offers [Section titled “Testing Intro Offers”](#testing-intro-offers) Use sandbox testing to verify behavior: ```typescript import { NativePurchases, PURCHASE_TYPE } from '@capgo/native-purchases'; // In sandbox mode, accelerated subscription durations apply: // - 3 days free trial = 3 minutes // - 1 week free trial = 3 minutes // - 1 month free trial = 5 minutes const { products } = await NativePurchases.getProducts({ productIdentifiers: ['premium_monthly'], productType: PURCHASE_TYPE.SUBS, }); // Purchase with intro offer const transaction = await NativePurchases.purchaseProduct({ productIdentifier: 'premium_monthly', productType: PURCHASE_TYPE.SUBS, }); console.log('Intro purchase transaction:', transaction.transactionId); // Wait for accelerated renewal setTimeout(async () => { const { purchases } = await NativePurchases.getPurchases({ productType: PURCHASE_TYPE.SUBS, }); const premium = purchases.find((purchase) => purchase.productIdentifier === 'premium_monthly'); console.log('After trial state:', premium?.subscriptionState); }, 180000); // 3 minutes for weekly trial ``` ## Important Notes [Section titled “Important Notes”](#important-notes) ### Eligibility Rules [Section titled “Eligibility Rules”](#eligibility-rules) * One intro offer per user per subscription group (lifetime) * Applies to new subscribers only * Cannot be used again after cancellation * Not available for subscription upgrades/crossgrades ### StoreKit API [Section titled “StoreKit API”](#storekit-api) * `introductoryPrice` shows intro offer details * `eligibility` method checks if user qualifies * Automatically applied at purchase time * No special purchase method needed ### Limitations [Section titled “Limitations”](#limitations) * Only one intro offer active per subscription at a time * Cannot combine with other discount types * Cannot change eligibility rules * Apple controls eligibility checking ## Troubleshooting [Section titled “Troubleshooting”](#troubleshooting) **Intro offer not showing:** * Check if offer is activated in App Store Connect * Verify user hasn’t used an intro offer before * Ensure user hasn’t subscribed to anything in the group * Test with new sandbox account **Eligibility check failing:** * Wait for App Store sync (can take 2-3 hours) * Verify product ID is correct * Check subscription group configuration * Test in sandbox with fresh test account **Wrong price displaying:** * Check regional pricing settings * Verify currency conversion * Ensure offer dates are current * Refresh product information **Sandbox testing issues:** * Use accelerated durations (3 min = 1 week) * Create new test accounts for each test * Wait for trial to complete naturally * Check renewal count (max 6 in sandbox) ## Analytics and Optimization [Section titled “Analytics and Optimization”](#analytics-and-optimization) ### Track These Metrics [Section titled “Track These Metrics”](#track-these-metrics) * Intro offer acceptance rate * Trial-to-paid conversion rate * Cancellation during trial * Retention after first charge * Revenue impact ### A/B Testing Ideas [Section titled “A/B Testing Ideas”](#ab-testing-ideas) * Free trial vs. paid intro * Trial length variations * Discount percentage * Single payment vs. recurring discount ### Optimization Strategy [Section titled “Optimization Strategy”](#optimization-strategy) ```typescript // Track offer performance analytics.track('intro_offer_displayed', { product_id: product.identifier, offer_type: product.introductoryPriceType, offer_duration: product.introductoryPricePeriod }); analytics.track('intro_offer_accepted', { product_id: product.identifier }); // Monitor conversion NativePurchases.addListener('transactionUpdated', (transaction) => { if (transaction.productIdentifier === product.identifier && transaction.isActive) { analytics.track('trial_converted', { transactionId: transaction.transactionId, productId: transaction.productIdentifier, }); } }); ``` ## Next Steps [Section titled “Next Steps”](#next-steps) * [Configure sandbox testing](/docs/plugins/native-purchases/ios-sandbox-testing/) to test your intro offers * Set up promotional offers for win-back campaigns * Implement subscription analytics * Create targeted marketing campaigns ## Additional Resources [Section titled “Additional Resources”](#additional-resources) For more details, refer to the [official Apple documentation on introductory offers](https://developer.apple.com/documentation/storekit/in-app_purchase/subscriptions_and_offers/implementing_introductory_offers_in_your_app). # Configure iOS Sandbox Testing > Learn how to set up sandbox testing for in-app purchases on iOS using App Store Connect and Xcode. Testing in-app purchases on iOS requires proper configuration in App Store Connect and on your test devices. This guide covers everything you need to get started with sandbox testing. ## Prerequisites [Section titled “Prerequisites”](#prerequisites) * **Apple Developer Program**: Active membership with annual renewal * **Agreements**: Signed “Paid Applications Agreement” with banking and tax information completed * **Xcode Project**: Configured with proper bundle identifier and capabilities Note Banking and tax setup approval can take hours to days. Complete this well in advance of testing. ## Setup Process [Section titled “Setup Process”](#setup-process) 1. **Sign Paid Applications Agreement** In App Store Connect, navigate to **Agreements, Tax, and Banking** and complete: * Sign the Paid Applications Agreement * Add your banking information * Complete tax forms Wait for Apple to approve your information (this can take 24-48 hours). 2. **Create Sandbox Test User** In App Store Connect, go to **Users and Access > Sandbox Testers**. Click the **+** button to create a new sandbox tester. **Important**: Use an email address that is NOT already associated with an Apple ID. You can use email aliases: * Gmail: `youremail+test@gmail.com` * iCloud: `youremail+test@icloud.com` ![Create sandbox tester](/native-purchases/ios/sandbox-testing/sandbox-tester-setup.webp) 3. **Configure Test Device (iOS 12+)** Starting with iOS 12, you no longer need to sign out of your iTunes account to test purchases. On your iOS device: 1. Open **Settings** 2. Tap **App Store** 3. Scroll to the bottom 4. Tap **Sandbox Account** 5. Sign in with your sandbox test account Tip This is much more convenient than the old method of signing out of your iTunes account! 4. **Configure Xcode Project** Ensure your Xcode project has: **Bundle Identifier** * Must match the identifier in your Developer Center * Must match the identifier in App Store Connect **In-App Purchase Capability** 1. Select your project in Xcode 2. Go to **Signing & Capabilities** 3. Click **+ Capability** 4. Add **In-App Purchase** 5. **Create In-App Purchase Products** In App Store Connect, navigate to your app and create your in-app purchase products (subscriptions, consumables, etc.). Products must be in at least “Ready to Submit” status for sandbox testing. 6. **Test Your Implementation** Build and run your app on a test device. When you attempt a purchase, you should see: > **\[Environment: Sandbox]** This confirmation indicates you’re in the sandbox environment and won’t be charged real money. ## Important Notes [Section titled “Important Notes”](#important-notes) ### Sandbox Environment Characteristics [Section titled “Sandbox Environment Characteristics”](#sandbox-environment-characteristics) * **No real charges**: All purchases are free in sandbox mode * **Accelerated subscriptions**: Subscription durations are shortened for faster testing * 1 week subscription = 3 minutes * 1 month subscription = 5 minutes * 2 months subscription = 10 minutes * 3 months subscription = 15 minutes * 6 months subscription = 30 minutes * 1 year subscription = 1 hour * **Auto-renewal limit**: Subscriptions auto-renew up to 6 times in sandbox * **Immediate cancellation**: Cancelled subscriptions expire immediately ### Sandbox Account Management [Section titled “Sandbox Account Management”](#sandbox-account-management) * Create multiple test accounts for different scenarios * Use test accounts only on test devices * Don’t use personal Apple ID for sandbox testing * Test accounts can purchase any product regardless of region ## Using Sandbox Testing [Section titled “Using Sandbox Testing”](#using-sandbox-testing) ```typescript import { NativePurchases, PURCHASE_TYPE } from '@capgo/native-purchases'; const { isBillingSupported } = await NativePurchases.isBillingSupported(); if (!isBillingSupported) { throw new Error('StoreKit not supported on this device'); } // Fetch products (automatically uses sandbox when available) const { products } = await NativePurchases.getProducts({ productIdentifiers: ['premium_monthly'], productType: PURCHASE_TYPE.SUBS, }); // Make test purchase const transaction = await NativePurchases.purchaseProduct({ productIdentifier: 'premium_monthly', productType: PURCHASE_TYPE.SUBS, }); console.log('Test purchase successful!', transaction.transactionId); ``` ## Verification [Section titled “Verification”](#verification) When properly configured, you should observe: 1. **Sandbox banner** during purchase: “\[Environment: Sandbox]” 2. **Products load** successfully 3. **Purchases complete** without actual charges 4. **Receipts validate** correctly 5. **Subscriptions renew** automatically (at accelerated rate) ## Troubleshooting [Section titled “Troubleshooting”](#troubleshooting) **Products not loading:** * Verify bundle identifier matches App Store Connect * Check that agreements are signed and approved * Ensure products are at least “Ready to Submit” status * Wait 2-3 hours after creating products **“Cannot connect to iTunes Store”:** * Verify sandbox account is configured correctly * Check device is connected to internet * Try signing out and back into sandbox account * Restart the app **Purchases failing silently:** * Check Xcode console for error messages * Verify In-App Purchase capability is enabled * Ensure sandbox account email is not a real Apple ID * Try creating a new sandbox test account **Receipt validation errors:** * Use sandbox receipt validation endpoint in testing * Production endpoint: `https://buy.itunes.apple.com/verifyReceipt` * Sandbox endpoint: `https://sandbox.itunes.apple.com/verifyReceipt` * The native-purchases plugin handles this automatically **Wrong subscription duration:** * Remember subscriptions are accelerated in sandbox * Use the conversion chart above for expected durations * Subscriptions auto-renew max 6 times in sandbox **“This Apple ID has not yet been used in the iTunes Store”:** * This is normal for new sandbox accounts * Proceed with the purchase to activate the account * Only happens on first use ## Best Practices [Section titled “Best Practices”](#best-practices) 1. **Create multiple test accounts** for different test scenarios 2. **Test all subscription durations** to verify behavior 3. **Test cancellation and renewal** flows 4. **Verify receipt validation** works correctly 5. **Test restore purchases** functionality 6. **Check subscription upgrade/downgrade** behavior 7. **Test with poor network conditions** ## Production vs. Sandbox [Section titled “Production vs. Sandbox”](#production-vs-sandbox) | Feature | Sandbox | Production | | --------------------- | ----------- | -------------- | | Real charges | No | Yes | | Subscription duration | Accelerated | Normal | | Auto-renewal limit | 6 times | Unlimited | | Cancellation effect | Immediate | End of period | | Receipt endpoint | Sandbox URL | Production URL | | Test accounts only | Yes | No | ## Additional Resources [Section titled “Additional Resources”](#additional-resources) For more details, refer to the [official Apple StoreKit documentation](https://developer.apple.com/documentation/storekit/in-app_purchase/testing_in-app_purchases_with_sandbox) on sandbox testing. # Create iOS Subscription Group > Learn how to create and configure subscription groups in App Store Connect for organizing your app's subscription offerings. Subscription groups are essential for organizing and managing multiple subscription levels in your iOS app. Understanding how they work is crucial for implementing upgrade, downgrade, and crossgrade functionality. ## What is a Subscription Group? [Section titled “What is a Subscription Group?”](#what-is-a-subscription-group) A subscription group is a collection of related subscriptions that users can choose between. Users can only subscribe to one subscription within a group at a time. When they switch subscriptions, Apple handles the transition automatically. ## Why Subscription Groups Matter [Section titled “Why Subscription Groups Matter”](#why-subscription-groups-matter) Subscription groups enable: * **Tiered pricing**: Offer basic, premium, and ultimate plans * **Different durations**: Monthly, yearly, and lifetime options * **Upgrade/downgrade logic**: Automatic handling of subscription changes * **Simplified management**: Group related subscriptions together ## Subscription Levels [Section titled “Subscription Levels”](#subscription-levels) Within a group, each subscription should be ranked from highest value (level 1) to lowest value. This ranking determines how subscription changes are classified: ![Subscription group hierarchy](/native-purchases/ios/subscription-group/subscription-group-hierarchy.webp) ### Level Examples [Section titled “Level Examples”](#level-examples) **Level 1** (Highest Value) * Premium Annual ($99.99/year) * Ultimate Monthly ($19.99/month) **Level 2** (Medium Value) * Standard Annual ($49.99/year) * Premium Monthly ($9.99/month) **Level 3** (Lowest Value) * Basic Annual ($29.99/year) * Standard Monthly ($4.99/month) ## Subscription Change Types [Section titled “Subscription Change Types”](#subscription-change-types) Apple automatically handles three types of subscription changes based on the level ranking: ### 1. Upgrade [Section titled “1. Upgrade”](#1-upgrade) Moving to a **higher-tier** subscription (e.g., level 2 → level 1). **Behavior:** * Takes effect **immediately** * User receives **prorated refund** for remaining time * New subscription starts right away **Example:** ```typescript // User currently has: Standard Monthly (Level 2) // User upgrades to: Premium Annual (Level 1) // Result: Immediate access to Premium, refund for unused Standard time ``` ### 2. Downgrade [Section titled “2. Downgrade”](#2-downgrade) Moving to a **lower-tier** subscription (e.g., level 1 → level 2). **Behavior:** * Takes effect at **next renewal date** * User keeps current subscription until period ends * New subscription starts automatically after expiration **Example:** ```typescript // User currently has: Premium Annual (Level 1) // User downgrades to: Standard Monthly (Level 2) // Result: Premium access continues until annual renewal date, then switches ``` ### 3. Crossgrade [Section titled “3. Crossgrade”](#3-crossgrade) Switching to another subscription **at the same tier level**. **Behavior depends on duration:** **Different Duration** → Behaves like **downgrade** * Takes effect at next renewal date * Example: Monthly Premium (Level 1) → Annual Premium (Level 1) **Same Duration** → Behaves like **upgrade** * Takes effect immediately * Example: Premium Monthly (Level 1) → Ultimate Monthly (Level 1) ## Creating a Subscription Group [Section titled “Creating a Subscription Group”](#creating-a-subscription-group) 1. **Navigate to Subscriptions** In App Store Connect, select your app and go to **Monetize > Subscriptions**. 2. **Create Group** Click **+** next to “Subscription Groups” to create a new group. 3. **Name the Group** Choose a descriptive name that reflects the subscriptions it contains: * “Premium Access” * “Cloud Storage Plans” * “Pro Features” 4. **Add Subscriptions** After creating the group, add individual subscriptions to it. Each subscription will have a level ranking. 5. **Set Level Rankings** Arrange subscriptions from highest value (1) to lowest value. Consider: * Annual plans typically rank higher than monthly * Higher-priced tiers rank above lower-priced ones * Ultimate/premium tiers rank highest ## Using in Your App [Section titled “Using in Your App”](#using-in-your-app) The native-purchases plugin automatically handles subscription group logic: ```typescript import { NativePurchases, PURCHASE_TYPE } from '@capgo/native-purchases'; // Fetch all subscriptions in a group const { products } = await NativePurchases.getProducts({ productIdentifiers: ['premium_monthly', 'premium_annual', 'ultimate_monthly'], productType: PURCHASE_TYPE.SUBS, }); // Display current subscription using StoreKit transactions const { purchases } = await NativePurchases.getPurchases({ productType: PURCHASE_TYPE.SUBS, }); const activeSubs = purchases.filter((purchase) => purchase.isActive); // Detect pending downgrade/cancellation (StoreKit sets willCancel === true) const pendingChange = purchases.find((purchase) => purchase.willCancel === true); if (pendingChange) { console.log('Subscription will stop auto-renewing on', pendingChange.expirationDate); } // Purchase (StoreKit handles upgrades/downgrades automatically) await NativePurchases.purchaseProduct({ productIdentifier: 'premium_annual', productType: PURCHASE_TYPE.SUBS, }); // Listen for StoreKit updates (fires on upgrades/downgrades/refunds) NativePurchases.addListener('transactionUpdated', (transaction) => { console.log('Subscription updated:', transaction); }); ``` ## Handling Subscription Changes [Section titled “Handling Subscription Changes”](#handling-subscription-changes) ### Detecting Change Type [Section titled “Detecting Change Type”](#detecting-change-type) ```typescript import { NativePurchases, PURCHASE_TYPE } from '@capgo/native-purchases'; // Get current subscription info const { purchases } = await NativePurchases.getPurchases({ productType: PURCHASE_TYPE.SUBS, }); const currentSubscription = purchases.find( (purchase) => purchase.subscriptionState === 'subscribed', ); if (currentSubscription) { // StoreKit reports if user cancelled auto-renew if (currentSubscription.willCancel) { console.log( `User cancelled. Access remains until ${currentSubscription.expirationDate}`, ); } if (currentSubscription.isUpgraded) { console.log('User recently upgraded to this plan.'); } } // Listen for automatic upgrades/downgrades NativePurchases.addListener('transactionUpdated', (transaction) => { console.log('Subscription changed!', transaction); if (transaction.subscriptionState === 'revoked') { revokeAccess(); } else if (transaction.isActive) { unlockPremiumFeatures(); } }); ``` ### User Communication [Section titled “User Communication”](#user-communication) Always communicate the change behavior clearly: **For Upgrades:** > “You’ll get immediate access to Premium features. We’ll prorate your current subscription.” **For Downgrades:** > “You’ll keep Premium access until \[renewal date], then switch to Standard.” **For Crossgrades:** > “Your plan will change to Annual billing at the next renewal on \[date].” ## Server monitoring [Section titled “Server monitoring”](#server-monitoring) Use Apple’s App Store Server Notifications v2 or your own receipt-validation backend to mirror StoreKit changes in your database. Pair server notifications with the `transactionUpdated` listener so both client and backend stay in sync. ## Best Practices [Section titled “Best Practices”](#best-practices) ### Group Organization [Section titled “Group Organization”](#group-organization) * Keep related subscriptions in the same group * Don’t mix unrelated features (e.g., storage and ad removal) * Create separate groups for different feature sets ### Level Ranking Strategy [Section titled “Level Ranking Strategy”](#level-ranking-strategy) * Annual plans → Higher level than monthly (for same tier) * Higher-priced tiers → Higher level * Consider value, not just price ### User Experience [Section titled “User Experience”](#user-experience) * Show current subscription clearly * Display all available options in the group * Indicate which changes are immediate vs. at renewal * Allow easy switching between plans ### Testing [Section titled “Testing”](#testing) * Test all upgrade scenarios * Test all downgrade scenarios * Verify crossgrade behavior * Check webhook firing ## Common Scenarios [Section titled “Common Scenarios”](#common-scenarios) ### Scenario 1: Three-Tier Monthly Plans [Section titled “Scenario 1: Three-Tier Monthly Plans”](#scenario-1-three-tier-monthly-plans) ```plaintext Level 1: Ultimate Monthly ($19.99) Level 2: Premium Monthly ($9.99) Level 3: Basic Monthly ($4.99) ``` * Basic → Premium: Upgrade (immediate) * Premium → Ultimate: Upgrade (immediate) * Ultimate → Premium: Downgrade (at renewal) * Basic → Ultimate: Upgrade (immediate) ### Scenario 2: Mixed Duration Plans [Section titled “Scenario 2: Mixed Duration Plans”](#scenario-2-mixed-duration-plans) ```plaintext Level 1: Premium Annual ($99.99/year) Level 2: Premium Monthly ($9.99/month) ``` * Monthly → Annual: Crossgrade (at renewal) * Annual → Monthly: Downgrade (at renewal) ### Scenario 3: Multi-Tier Multi-Duration [Section titled “Scenario 3: Multi-Tier Multi-Duration”](#scenario-3-multi-tier-multi-duration) ```plaintext Level 1: Ultimate Annual ($199/year) Level 2: Ultimate Monthly ($19.99/month) Level 3: Premium Annual ($99/year) Level 4: Premium Monthly ($9.99/month) Level 5: Basic Annual ($49/year) Level 6: Basic Monthly ($4.99/month) ``` This setup provides maximum flexibility while maintaining clear upgrade/downgrade logic. ## Troubleshooting [Section titled “Troubleshooting”](#troubleshooting) **Subscription not appearing in group:** * Verify it’s assigned to the correct group * Check that it’s in at least “Ready to Submit” status * Ensure product ID is correct **Wrong upgrade/downgrade behavior:** * Review level rankings (1 = highest) * Verify subscription tiers make sense * Check that levels are set correctly **Products from different groups:** * Users can subscribe to multiple groups simultaneously * This is intentional - keep related products in same group **getActiveProducts showing multiple subscriptions:** * Check if subscriptions are in different groups * Verify user isn’t subscribed via Family Sharing * Review subscription status in App Store Connect ## Additional Resources [Section titled “Additional Resources”](#additional-resources) For more details, refer to the [official Apple documentation on subscription groups](https://developer.apple.com/app-store/subscriptions/). # Revenue Playbook > Learn how to turn a Capacitor app into revenue with a focused MVP, store discovery, paywall placement, pricing, analytics, and @capgo/native-purchases. ![Revenue playbook for in-app purchases](/native-purchases/revenue-playbook.png) The purchase SDK is only one part of making money from an app. Revenue comes from a clear problem, a small product that users can try, reliable store billing, and a paywall that teaches you what people are willing to buy. Use this playbook when you are adding subscriptions or premium unlocks with `@capgo/native-purchases`. ## Start with a simple revenue target [Section titled “Start with a simple revenue target”](#start-with-a-simple-revenue-target) Make the first target concrete. For example: | Monthly price | Active subscribers needed for about $1K MRR | | ------------- | ------------------------------------------------- | | $4.99 | 201 | | $7.99 | 126 | | $9.99 | 101 | | $29.99 yearly | About 400 annual subscribers, depending on timing | These numbers are before store fees, taxes, refunds, and currency differences. They are still useful because they keep the launch plan practical: you need a few hundred motivated users, not a huge audience. ## Build the smallest paid product [Section titled “Build the smallest paid product”](#build-the-smallest-paid-product) 1. **Pick one painful use case** Build around one outcome users already search for. Examples: a workout plan for new parents, a budget tracker for couples, a receipt scanner for freelancers, or a language drill app for one exam. 2. **Check demand in the stores** Search App Store and Google Play for the core keyword. Read low and mid-score reviews of competing apps to find missing features, confusing onboarding, pricing complaints, and UI friction. 3. **Ship a narrow MVP** The first version should include onboarding, one useful core action, basic error handling, and enough analytics to see whether users reach the value moment. 4. **Add purchases early** Do not wait until the app feels complete. A basic paywall helps you learn whether users understand the value and whether your pricing is plausible. ## Instrument the funnel before optimizing [Section titled “Instrument the funnel before optimizing”](#instrument-the-funnel-before-optimizing) Track these events before you start changing prices or screens: | Event | Why it matters | | ----------------------------------------- | --------------------------------------- | | `install` or first open | Baseline traffic | | `onboarding_completed` | Whether users understand the setup | | `core_action_completed` | Whether the product delivers value | | `paywall_viewed` | Whether users reach monetization | | `trial_started` | Whether the offer is compelling | | `purchase_completed` | Paid conversion | | `restore_started` and `restore_completed` | Purchase recovery and review compliance | | `subscription_status_checked` | Entitlement reliability | | `cancel_feedback_submitted` | Churn reason | If many users do not see the paywall, fix onboarding before changing the paywall. If users see the paywall but do not start a trial, improve the offer, proof, or price presentation. ## Choose one monetization model [Section titled “Choose one monetization model”](#choose-one-monetization-model) Start with one model so the data is readable. | Model | Good fit | First version | | ----------------------- | ------------------------------------------------ | -------------------------------------------------------- | | Freemium | Daily utilities, trackers, tools with repeat use | Free core action, paid limits or premium features | | Paywall plus free trial | Apps that deliver quick value after onboarding | Paywall after onboarding with 3- to 14-day trial | | One-time unlock | Small tools with limited recurring value | Lifetime product plus optional future subscription later | Avoid shipping three tiers, many bundles, and complex upgrade paths on day one. Use one monthly plan and one annual plan when you need subscriptions. Add localized pricing after you see meaningful traffic from a country. ## Configure products for revenue learning [Section titled “Configure products for revenue learning”](#configure-products-for-revenue-learning) Keep product identifiers stable and readable: ```text com.example.app.premium.monthly com.example.app.premium.yearly com.example.app.premium.lifetime ``` Use store product names that reinforce the value users are searching for, such as “Meal Planner Pro Monthly” instead of only “Monthly”. Store metadata and in-app purchase names can help discovery and clarity. Load product data from the stores so pricing, currency, and introductory offers are always accurate: ```typescript import { NativePurchases, PURCHASE_TYPE } from '@capgo/native-purchases'; const { products } = await NativePurchases.getProducts({ productIdentifiers: [ 'com.example.app.premium.monthly', 'com.example.app.premium.yearly', ], productType: PURCHASE_TYPE.SUBS, }); const monthly = products.find((product) => product.identifier.endsWith('.monthly')); const yearly = products.find((product) => product.identifier.endsWith('.yearly')); ``` Never hardcode store pricing in the UI. Render `product.priceString`, localized product title, billing period, and trial terms from store data whenever possible. ## Build a first paywall [Section titled “Build a first paywall”](#build-a-first-paywall) A first paywall should be clear, not clever: * Headline: the paid outcome, such as “Unlock unlimited workout plans”. * Benefits: 3 to 5 concrete improvements, not a long feature list. * Plans: monthly and annual, with real annual savings if offered. * Trial: exact trial length and what happens after it ends. * CTA: “Start free trial” or “Upgrade now”. * Links: terms, privacy policy, restore purchases, and manage subscriptions. Place the first paywall after onboarding, once the user understands what the app does. Later, test additional triggers such as usage limits, premium feature taps, or completed core actions. ## Purchase and restore flow [Section titled “Purchase and restore flow”](#purchase-and-restore-flow) ```typescript import { NativePurchases, PURCHASE_TYPE } from '@capgo/native-purchases'; export async function buyYearly(appAccountToken: string) { const transaction = await NativePurchases.purchaseProduct({ productIdentifier: 'com.example.app.premium.yearly', planIdentifier: 'yearly-plan', productType: PURCHASE_TYPE.SUBS, appAccountToken, }); await fetch('/api/purchases/validate', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ transactionId: transaction.transactionId, receipt: transaction.receipt, purchaseToken: transaction.purchaseToken, productIdentifier: transaction.productIdentifier, }), }); return transaction; } export async function restorePurchases() { await NativePurchases.restorePurchases(); return NativePurchases.getPurchases({ productType: PURCHASE_TYPE.SUBS, }); } ``` Always validate purchases on your backend before granting durable entitlements. Keep a local entitlement cache for fast UI, but treat the store and your backend as the source of truth. ## Bring in the first users [Section titled “Bring in the first users”](#bring-in-the-first-users) Revenue needs traffic. Start with channels that can work before you have a brand: * ASO: title, subtitle, keywords, screenshots, app description, icon, ratings, and in-app purchase names. * Short-form video: post quick demos, problem/solution clips, and before/after examples for the target country. * Reddit and communities: join the conversation first, then share what you built as a useful story instead of an ad. * Beta groups: TestFlight, Google Play internal testing, Discord, and niche forums. Each channel should send users into the same measured funnel so you can compare retention, paywall views, trials, and purchases. ## Read churn correctly [Section titled “Read churn correctly”](#read-churn-correctly) Some churn means users tried the app and decided it was not for them. That is normal. What matters is the pattern: * Cancels during trial: unclear value, poor onboarding, or wrong traffic. * Cancels after one cycle: not enough repeat value or weak habit loop. * Refunds: pricing mismatch, accidental purchase risk, or unclear terms. * No restores: broken entitlement handling or missing restore UI. Add a one-question cancellation survey when possible. Use the answers to improve onboarding, feature scope, store screenshots, and paywall copy. ## Launch checklist [Section titled “Launch checklist”](#launch-checklist) * Product solves one clear paid problem. * Store products are active and tested on iOS and Android. * Paywall displays store-loaded prices and terms. * Purchase, restore, manage subscription, and backend validation are implemented. * Funnel events are tracked from first open to purchase. * App store metadata explains the value in the first screenshots. * At least one acquisition channel is active before launch. * Churn feedback is collected from the first subscribers. ## Related guides [Section titled “Related guides”](#related-guides) * [Getting started](/docs/plugins/native-purchases/getting-started/) * [Create iOS subscriptions](/docs/plugins/native-purchases/ios-create-subscription/) * [Create Android subscriptions](/docs/plugins/native-purchases/android-create-subscription/) * [iOS sandbox testing](/docs/plugins/native-purchases/ios-sandbox-testing/) * [Android sandbox testing](/docs/plugins/native-purchases/android-sandbox-testing/) # @capgo/nativegeocoder > Capacitor plugin for native forward and reverse geocoding. ## Overview [Section titled “Overview”](#overview) Capacitor plugin for native forward and reverse geocoding. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `reverseGeocode` - Convert latitude and longitude to an address. * `forwardGeocode` - Convert an address to latitude and longitude. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------ | --------------------------------------------- | | `reverseGeocode` | Convert latitude and longitude to an address. | | `forwardGeocode` | Convert an address to latitude and longitude. | | `getPluginVersion` | Get the native Capacitor plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-nativegeocoder](https://github.com/Cap-go/capacitor-nativegeocoder/). # Getting Started > Install @capgo/nativegeocoder and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/nativegeocoder bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { NativeGeocoder } from '@capgo/nativegeocoder'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `reverseGeocode` [Section titled “reverseGeocode”](#reversegeocode) Convert latitude and longitude to an address ```typescript import { NativeGeocoder } from '@capgo/nativegeocoder'; await NativeGeocoder.reverseGeocode({} as ReverseOptions); ``` ### `forwardGeocode` [Section titled “forwardGeocode”](#forwardgeocode) Convert an address to latitude and longitude ```typescript import { NativeGeocoder } from '@capgo/nativegeocoder'; await NativeGeocoder.forwardGeocode({} as ForwardOptions); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `ReverseOptions` [Section titled “ReverseOptions”](#reverseoptions) ```typescript export interface ReverseOptions { /** * latitude is a number representing the latitude of the location. */ latitude: number; /** * longitude is a number representing the longitude of the location. */ longitude: number; /** * Localise the results to the given locale. */ useLocale?: boolean; /** * locale is a string in the format of language_country, for example en_US. */ defaultLocale?: string; /** * Max number of results to return. */ maxResults?: number; /** * Only used for web platform to use google api */ apiKey?: string; /** * Only used for web platform to use google api */ resultType?: string; } ``` ### `Address` [Section titled “Address”](#address) ```typescript export interface Address { latitude: number; longitude: number; countryCode: string; countryName: string; postalCode: string; administrativeArea: string; subAdministrativeArea: string; locality: string; subLocality: string; thoroughfare: string; subThoroughfare: string; areasOfInterest: string[]; } ``` ### `ForwardOptions` [Section titled “ForwardOptions”](#forwardoptions) ```typescript export interface ForwardOptions { /** * address is a string of the address to be geocoded. */ addressString: string; /** * Localise the results to the given locale. */ useLocale?: boolean; /** * locale is a string in the format of language_country, for example en_US. */ defaultLocale?: string; /** * Max number of results to return. */ maxResults?: number; /** * Only used for web platform to use google api */ apiKey?: string; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-navigation-bar > Capacitor Navigation Bar Plugin for customizing the Android navigation bar. ## Overview [Section titled “Overview”](#overview) Capacitor Navigation Bar Plugin for customizing the Android navigation bar. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `setNavigationBarColor` - Set the navigation bar color and button theme. * `getNavigationBarColor` - Get the current navigation bar color and button theme. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ----------------------- | ------------------------------------------------------ | | `setNavigationBarColor` | Set the navigation bar color and button theme. | | `getNavigationBarColor` | Get the current navigation bar color and button theme. | | `getPluginVersion` | Get the native Capacitor plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-navigation-bar](https://github.com/Cap-go/capacitor-navigation-bar/). # Getting Started > Install @capgo/capacitor-navigation-bar and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-navigation-bar bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { NavigationBar } from '@capgo/capacitor-navigation-bar'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `setNavigationBarColor` [Section titled “setNavigationBarColor”](#setnavigationbarcolor) Set the navigation bar color and button theme. ```typescript import { NavigationBar } from '@capgo/capacitor-navigation-bar'; // Set to white with dark buttons await NavigationBar.setNavigationBarColor({ color: NavigationBarColor.WHITE, darkButtons: true }); // Set to custom color await NavigationBar.setNavigationBarColor({ color: '#FF5733', darkButtons: false }); // Set a custom divider color on Android 9+ await NavigationBar.setNavigationBarColor({ color: NavigationBarColor.WHITE, darkButtons: true, dividerColor: '#D9D9D9' }); ``` ### `getNavigationBarColor` [Section titled “getNavigationBarColor”](#getnavigationbarcolor) Get the current navigation bar color and button theme. ```typescript import { NavigationBar } from '@capgo/capacitor-navigation-bar'; const { color, darkButtons } = await NavigationBar.getNavigationBarColor(); console.log('Current color:', color); console.log('Using dark buttons:', darkButtons); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `NavigationBarColor` [Section titled “NavigationBarColor”](#navigationbarcolor) Predefined navigation bar colors. ```typescript export enum NavigationBarColor { /** White color */ WHITE = '#FFFFFF', /** Black color */ BLACK = '#000000', /** Transparent color */ TRANSPARENT = 'transparent', } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-nfc > Public API surface for the Capacitor NFC plugin. ## Overview [Section titled “Overview”](#overview) Public API surface for the Capacitor NFC plugin. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `startScanning` - Starts listening for NFC tags. * `stopScanning` - Stops the ongoing NFC scanning session. * `write` - Writes the provided NDEF records to the last discovered tag. * `erase` - Attempts to erase the last discovered tag by writing an empty NDEF message. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------ | --------------------------------------------------------------------------- | | `startScanning` | Starts listening for NFC tags. | | `stopScanning` | Stops the ongoing NFC scanning session. | | `write` | Writes the provided NDEF records to the last discovered tag. | | `erase` | Attempts to erase the last discovered tag by writing an empty NDEF message. | | `makeReadOnly` | Attempts to make the last discovered tag read-only. | | `share` | Shares an NDEF message with another device via peer-to-peer (Android only). | | `unshare` | Stops sharing previously provided NDEF message (Android only). | | `getStatus` | Returns the current NFC adapter status. | | `showSettings` | Opens the system settings page where the user can enable NFC. | | `getPluginVersion` | Returns the version string baked into the native plugin. | | `isSupported` | Checks whether the device has NFC hardware support. | | `addListener` | See the source definitions for current behavior. | | `addListener` | See the source definitions for current behavior. | | `addListener` | See the source definitions for current behavior. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-nfc](https://github.com/Cap-go/capacitor-nfc/). # Getting Started > Install @capgo/capacitor-nfc and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-nfc bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { CapacitorNfc } from '@capgo/capacitor-nfc'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `startScanning` [Section titled “startScanning”](#startscanning) Starts listening for NFC tags. ```typescript import { CapacitorNfc } from '@capgo/capacitor-nfc'; await CapacitorNfc.startScanning(); ``` ### `stopScanning` [Section titled “stopScanning”](#stopscanning) Stops the ongoing NFC scanning session. ```typescript import { CapacitorNfc } from '@capgo/capacitor-nfc'; await CapacitorNfc.stopScanning(); ``` ### `write` [Section titled “write”](#write) Writes the provided NDEF records to the last discovered tag. ```typescript import { CapacitorNfc } from '@capgo/capacitor-nfc'; await CapacitorNfc.write({} as WriteTagOptions); ``` ### `erase` [Section titled “erase”](#erase) Attempts to erase the last discovered tag by writing an empty NDEF message. ```typescript import { CapacitorNfc } from '@capgo/capacitor-nfc'; await CapacitorNfc.erase(); ``` ### `makeReadOnly` [Section titled “makeReadOnly”](#makereadonly) Attempts to make the last discovered tag read-only. ```typescript import { CapacitorNfc } from '@capgo/capacitor-nfc'; await CapacitorNfc.makeReadOnly(); ``` ### `share` [Section titled “share”](#share) Shares an NDEF message with another device via peer-to-peer (Android only). ```typescript import { CapacitorNfc } from '@capgo/capacitor-nfc'; await CapacitorNfc.share({} as ShareTagOptions); ``` ### `unshare` [Section titled “unshare”](#unshare) Stops sharing previously provided NDEF message (Android only). ```typescript import { CapacitorNfc } from '@capgo/capacitor-nfc'; await CapacitorNfc.unshare(); ``` ### `getStatus` [Section titled “getStatus”](#getstatus) Returns the current NFC adapter status. ```typescript import { CapacitorNfc } from '@capgo/capacitor-nfc'; await CapacitorNfc.getStatus(); ``` ### `showSettings` [Section titled “showSettings”](#showsettings) Opens the system settings page where the user can enable NFC. ```typescript import { CapacitorNfc } from '@capgo/capacitor-nfc'; await CapacitorNfc.showSettings(); ``` ### `isSupported` [Section titled “isSupported”](#issupported) Checks whether the device has NFC hardware support. Returns `true` if NFC hardware is present on the device, regardless of whether NFC is currently enabled or disabled. Returns `false` if the device does not have NFC hardware. Use this method to determine if NFC features should be shown in your app’s UI. To check if NFC is currently enabled, use `getStatus()`. ```typescript import { CapacitorNfc } from '@capgo/capacitor-nfc'; await CapacitorNfc.isSupported(); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `StartScanningOptions` [Section titled “StartScanningOptions”](#startscanningoptions) Options controlling the behaviour of . ```typescript export interface StartScanningOptions { /** * iOS-only: closes the NFC session automatically after the first successful tag read. * Defaults to `true`. */ invalidateAfterFirstRead?: boolean; /** * iOS-only: custom message displayed in the NFC system sheet while scanning. */ alertMessage?: string; /** * iOS-only: session type to use for NFC scanning. * - `'ndef'`: Uses NFCNDEFReaderSession (default). Only detects NDEF-formatted tags. * - `'tag'`: Uses NFCTagReaderSession. Detects both NDEF and non-NDEF tags (e.g., raw MIFARE tags). * Allows reading UID from unformatted tags. * **Requires** the `Near Field Communication Tag Reader Session Formats` entitlement * in your app with the `TAG` format included. Without it the session will fail to * start and the promise will reject with a `NO_NFC` error code. * Defaults to `'ndef'` for backward compatibility. */ iosSessionType?: 'ndef' | 'tag'; /** * Android-only: raw flags passed to `NfcAdapter.enableReaderMode`. * Defaults to enabling all tag types with skipping NDEF checks. */ androidReaderModeFlags?: number; } ``` ### `WriteTagOptions` [Section titled “WriteTagOptions”](#writetagoptions) Options used when writing an NDEF message on the current tag. ```typescript export interface WriteTagOptions { /** * Array of records that compose the NDEF message to be written. */ records: NdefRecord[]; /** * When `true`, the plugin attempts to format NDEF-formattable tags before writing. * Defaults to `true`. */ allowFormat?: boolean; } ``` ### `ShareTagOptions` [Section titled “ShareTagOptions”](#sharetagoptions) Options used when sharing an NDEF message with another device using Android Beam / P2P mode. ```typescript export interface ShareTagOptions { records: NdefRecord[]; } ``` ### `NfcStatus` [Section titled “NfcStatus”](#nfcstatus) Possible NFC adapter states returned by . ```typescript export type NfcStatus = 'NFC_OK' | 'NO_NFC' | 'NFC_DISABLED' | 'NDEF_PUSH_DISABLED'; ``` ### `NfcEvent` [Section titled “NfcEvent”](#nfcevent) Generic NFC discovery event dispatched by the plugin. ```typescript export interface NfcEvent { type: NfcEventType; tag: NfcTag; } ``` ### `NfcStateChangeEvent` [Section titled “NfcStateChangeEvent”](#nfcstatechangeevent) Event emitted whenever the NFC adapter availability changes. ```typescript export interface NfcStateChangeEvent { status: NfcStatus; enabled: boolean; } ``` ### `NdefRecord` [Section titled “NdefRecord”](#ndefrecord) JSON structure representing a single NDEF record. ```typescript export interface NdefRecord { /** * Type Name Format identifier. */ tnf: number; /** * Type field expressed as an array of byte values. */ type: number[]; /** * Record identifier expressed as an array of byte values. */ id: number[]; /** * Raw payload expressed as an array of byte values. */ payload: number[]; } ``` ### `NfcEventType` [Section titled “NfcEventType”](#nfceventtype) Event type describing the kind of NFC discovery that happened. ```typescript export type NfcEventType = 'tag' | 'ndef' | 'ndef-mime' | 'ndef-formatable'; ``` ### `NfcTag` [Section titled “NfcTag”](#nfctag) Representation of the full tag information returned by the native layers. ```typescript export interface NfcTag { /** * Raw identifier bytes for the tag. */ id?: number[]; /** * List of Android tech strings (e.g. `android.nfc.tech.Ndef`). */ techTypes?: string[]; /** * Human readable tag type when available (e.g. `NFC Forum Type 2`, `MIFARE Ultralight`). */ type?: string | null; /** * Maximum writable size in bytes for tags that expose NDEF information. */ maxSize?: number | null; /** * Indicates whether the tag can be written to. */ isWritable?: boolean | null; /** * Indicates whether the tag can be permanently locked. */ canMakeReadOnly?: boolean | null; /** * Array of NDEF records discovered on the tag. */ ndefMessage?: NdefRecord[] | null; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-passkey > Keep your browser-style WebAuthn code in a Capacitor app while the plugin handles native passkey calls and native host patching. Browser-style API Keep `navigator.credentials.create()` and `navigator.credentials.get()` in your app instead of rewriting your passkey flow around a custom API. Minimal app changes Add plugin config once, call `CapacitorPasskey.autoShimWebAuthn()` during bootstrap, and keep the rest of your WebAuthn code close to the browser implementation. Build-time native wiring The plugin patches the generated iOS and Android host projects during sync so you do not need to keep hand-editing those files. Platform notes included Follow the [Getting Started](/docs/plugins/passkey/getting-started/), [iOS setup](/docs/plugins/passkey/ios/), [Android setup](/docs/plugins/passkey/android/), and [backend notes](/docs/plugins/passkey/backend/). ## Core API [Section titled “Core API”](#core-api) * `shimWebAuthn(options?)` installs the browser-style shim immediately, with an optional HTTPS origin override. * `getConfiguration()` reads the resolved runtime config from `plugins.CapacitorPasskey`. * `autoShimWebAuthn(options?)` reads that config and installs the shim in one step during app bootstrap. * `createCredential(options)` and `getCredential(options)` call the native passkey APIs directly with JSON-safe WebAuthn payloads. * `isSupported()` reports runtime availability and `getPluginVersion()` returns the native implementation version marker. # Android Setup > Configure passkeys on Android for @capgo/capacitor-passkey with Digital Asset Links and assetlinks.json. On Android, passkeys work with your website when the app and the relying-party domain are connected through Digital Asset Links. ## What the plugin handles [Section titled “What the plugin handles”](#what-the-plugin-handles) After you add the plugin config and run `bunx cap sync`, the plugin patches the generated Android host project: * injects the `asset_statements` manifest metadata * writes the generated string resource referenced by that metadata ## What you still need to host [Section titled “What you still need to host”](#what-you-still-need-to-host) You must publish `assetlinks.json` on the relying-party domain: ```text https://signin.example.com/.well-known/assetlinks.json ``` Example: ```json [ { "relation": [ "delegate_permission/common.handle_all_urls", "delegate_permission/common.get_login_creds" ], "target": { "namespace": "android_app", "package_name": "app.capgo.passkey.example", "sha256_cert_fingerprints": [ "AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99" ] } } ] ``` ## Checklist [Section titled “Checklist”](#checklist) 1. Set `origin` and `domains` in `plugins.CapacitorPasskey` in `capacitor.config.*`. 2. Run `bunx cap sync`. 3. Use your real Android package name in `assetlinks.json`. 4. Add every signing certificate fingerprint you need, including debug or internal signing keys if you test those builds. 5. Host the file on the same domain you use as the relying-party ID. ## Important behavior difference from a browser [Section titled “Important behavior difference from a browser”](#important-behavior-difference-from-a-browser) With Digital Asset Links configured, Android can use the same relying party and passkeys as your website. The remaining difference is the literal origin reported in native `clientDataJSON`. * A normal Android app does not behave like a privileged browser. * The assertion origin can be tied to the Android app signature instead of your website origin. * If your backend strictly validates `clientDataJSON.origin`, accept the Android app origin alongside the website origin. # Backend Notes > Understand the backend contract for @capgo/capacitor-passkey, including WebAuthn challenge handling and Android origin validation. Your backend still owns the normal WebAuthn ceremony: * generate registration and authentication challenges * verify attestation and assertion responses * enforce relying-party ID and challenge validation * store credentials and counters the same way you would for a browser flow ## What stays the same [Section titled “What stays the same”](#what-stays-the-same) The plugin is designed to preserve the front-end shape of your existing WebAuthn code. * On the web, it forwards to the real browser WebAuthn API. * On native Capacitor, it returns browser-like credential objects backed by native passkey APIs. * Your backend can keep the same challenge and verification pipeline. ## What changes on Android [Section titled “What changes on Android”](#what-changes-on-android) Android native passkeys are not identical to a browser trust model. * Digital Asset Links let Android share the same relying party and credential ecosystem as your website. * The literal `clientDataJSON.origin` value can still differ from the website origin. * If your server rejects anything except `https://your-domain`, Android native assertions can fail even when the passkey is otherwise valid. ## Recommended backend rule [Section titled “Recommended backend rule”](#recommended-backend-rule) Allow the expected browser origin and the expected Android app origin for the same relying party when you support native Android passkeys. That gives you: * browser support for the website * native passkey support in the Capacitor app * one passkey ecosystem for the same relying-party domain ## If you need direct JSON-safe calls [Section titled “If you need direct JSON-safe calls”](#if-you-need-direct-json-safe-calls) If your backend already returns `PublicKeyCredentialCreationOptionsJSON` and `PublicKeyCredentialRequestOptionsJSON`, you can also use the direct plugin API instead of the browser-style shim: ```ts import { CapacitorPasskey } from '@capgo/capacitor-passkey'; const registration = await CapacitorPasskey.createCredential({ origin: 'https://signin.example.com', publicKey: registrationOptionsFromBackend, }); const authentication = await CapacitorPasskey.getCredential({ origin: 'https://signin.example.com', publicKey: requestOptionsFromBackend, }); ``` # Getting Started > Install @capgo/capacitor-passkey, configure the plugin once, and keep your browser-style WebAuthn code in a Capacitor app. 1. **Install the package** ```sh bun add @capgo/capacitor-passkey ``` 2. **Sync native projects** ```sh bunx cap sync ``` 3. **Add the plugin config** ```ts import type { CapacitorConfig } from '@capacitor/cli'; const config: CapacitorConfig = { appId: 'app.capgo.passkey.example', appName: 'My App', webDir: 'dist', plugins: { CapacitorPasskey: { origin: 'https://signin.example.com', autoShim: true, domains: ['signin.example.com'], }, }, }; export default config; ``` 4. **Install the shim during bootstrap** ```ts import { CapacitorPasskey } from '@capgo/capacitor-passkey'; await CapacitorPasskey.autoShimWebAuthn(); ``` 5. **Keep your normal WebAuthn flow** ```ts const registration = await navigator.credentials.create({ publicKey: registrationOptions, }); const authentication = await navigator.credentials.get({ publicKey: requestOptions, }); ``` ## What the plugin config does [Section titled “What the plugin config does”](#what-the-plugin-config-does) The config is read from `plugins.CapacitorPasskey` in `capacitor.config.*`. * `origin`: primary HTTPS relying-party origin used by the shim and direct API * `domains`: extra relying-party hostnames to patch into native config during sync * `autoShim`: defaults to `true` and controls the native `cap sync` auto-configuration hook ## What sync patches for you [Section titled “What sync patches for you”](#what-sync-patches-for-you) When you run `bunx cap sync`, the plugin updates the generated native host project: * iOS: associated domains entitlements and Xcode entitlements wiring when needed * Android: `asset_statements` metadata and the generated resource used by the manifest The hook does not publish your website trust files for you. You still need to host: * `https://your-domain/.well-known/apple-app-site-association` * `https://your-domain/.well-known/assetlinks.json` ## Platform guides [Section titled “Platform guides”](#platform-guides) [ iOS setup](/docs/plugins/passkey/ios/) [Associated Domains and `apple-app-site-association`.](/docs/plugins/passkey/ios/) [ Android setup](/docs/plugins/passkey/android/) [Digital Asset Links and `assetlinks.json`.](/docs/plugins/passkey/android/) [ Backend notes](/docs/plugins/passkey/backend/) [Origin validation and Android caveats.](/docs/plugins/passkey/backend/) # iOS Setup > Configure passkeys on iOS for @capgo/capacitor-passkey with Associated Domains and the apple-app-site-association file. On iOS, passkeys only work when the app is associated with the same relying-party domain as the website. ## What the plugin handles [Section titled “What the plugin handles”](#what-the-plugin-handles) After you add the plugin config and run `bunx cap sync`, the plugin patches the generated iOS host project so you do not need to keep editing it manually: * adds the `webcredentials:` associated domains entries for the configured domains * wires `CODE_SIGN_ENTITLEMENTS` when the generated app target does not already point at an entitlements file ## What you still need to host [Section titled “What you still need to host”](#what-you-still-need-to-host) You must publish `apple-app-site-association` on the relying-party domain: ```text https://signin.example.com/.well-known/apple-app-site-association ``` Example: ```json { "webcredentials": { "apps": ["ABCDE12345.app.capgo.passkey.example"] } } ``` ## Checklist [Section titled “Checklist”](#checklist) 1. Set `origin` and `domains` in `plugins.CapacitorPasskey` in `capacitor.config.*`. 2. Run `bunx cap sync`. 3. Confirm your Apple Team ID and app bundle ID, then build the `TEAMID.bundleId` value for the association file. 4. Host `apple-app-site-association` with HTTP `200` and no `.json` extension. 5. Make sure the relying-party ID used by your backend matches the associated domain. ## Notes [Section titled “Notes”](#notes) * The website file must be served from the exact passkey domain you use as the relying-party ID. * On iOS 17.4 and newer, the plugin uses the browser-style client-data API so the configured HTTPS origin is reflected in `clientDataJSON`. * The plugin can patch native project files during sync, but it cannot create or host the website association file on your domain. # @capgo/capacitor-pay > Capacitor plugin to trigger native payment for iOS(Apple pay) and Android(Google Pay). ## Overview [Section titled “Overview”](#overview) Capacitor plugin to trigger native payment for iOS(Apple pay) and Android(Google Pay). ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `isPayAvailable` - Checks whether native pay is available on the current platform. On iOS this evaluates Apple Pay, on Android it evaluates Google Pay. * `requestPayment` - Presents the native pay sheet for the current platform. Provide the Apple Pay configuration on iOS and the Google Pay configuration on Android. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------- | | `isPayAvailable` | Checks whether native pay is available on the current platform. On iOS this evaluates Apple Pay, on Android it evaluates Google Pay. | | `requestPayment` | Presents the native pay sheet for the current platform. Provide the Apple Pay configuration on iOS and the Google Pay configuration on Android. | | `getPluginVersion` | Get the native Capacitor plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-pay](https://github.com/Cap-go/capacitor-pay/). # Getting Started > Install @capgo/capacitor-pay and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-pay bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { Pay } from '@capgo/capacitor-pay'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `isPayAvailable` [Section titled “isPayAvailable”](#ispayavailable) Checks whether native pay is available on the current platform. On iOS this evaluates Apple Pay, on Android it evaluates Google Pay. ```typescript import { Pay } from '@capgo/capacitor-pay'; await Pay.isPayAvailable(); ``` ### `requestPayment` [Section titled “requestPayment”](#requestpayment) Presents the native pay sheet for the current platform. Provide the Apple Pay configuration on iOS and the Google Pay configuration on Android. This promise is the completion path on both platforms. ```typescript import { Pay } from '@capgo/capacitor-pay'; await Pay.requestPayment({} as PayPaymentOptions); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `PayAvailabilityOptions` [Section titled “PayAvailabilityOptions”](#payavailabilityoptions) ```typescript export interface PayAvailabilityOptions { apple?: ApplePayAvailabilityOptions; google?: GooglePayAvailabilityOptions; } ``` ### `PayAvailabilityResult` [Section titled “PayAvailabilityResult”](#payavailabilityresult) ```typescript export interface PayAvailabilityResult { available: boolean; platform: PayPlatform; apple?: ApplePayAvailabilityResult; google?: GooglePayAvailabilityResult; } ``` ### `PayPaymentOptions` [Section titled “PayPaymentOptions”](#paypaymentoptions) ```typescript export interface PayPaymentOptions { apple?: ApplePayPaymentOptions; google?: GooglePayPaymentOptions; } ``` ### `PayPaymentResult` [Section titled “PayPaymentResult”](#paypaymentresult) ```typescript export type PayPaymentResult = ApplePayRequestPaymentResult | GooglePayRequestPaymentResult; ``` ### `ApplePayAvailabilityOptions` [Section titled “ApplePayAvailabilityOptions”](#applepayavailabilityoptions) ```typescript export interface ApplePayAvailabilityOptions { /** * Optional list of payment networks you intend to use. * Passing networks determines the return value of `canMakePaymentsUsingNetworks`. */ supportedNetworks?: ApplePayNetwork[]; } ``` ### `GooglePayAvailabilityOptions` [Section titled “GooglePayAvailabilityOptions”](#googlepayavailabilityoptions) ```typescript export interface GooglePayAvailabilityOptions { /** * Environment used to construct the Google Payments client. Defaults to `'test'`. */ environment?: GooglePayEnvironment; /** * Raw `IsReadyToPayRequest` JSON as defined by the Google Pay API. * Supply the card networks and auth methods you intend to support at runtime. * * @see https://developers.google.com/pay/api/android/reference/request-objects#IsReadyToPayRequest */ isReadyToPayRequest?: GooglePayIsReadyToPayRequest; } ``` ### `PayPlatform` [Section titled “PayPlatform”](#payplatform) ```typescript export type PayPlatform = 'ios' | 'android' | 'web'; ``` ### `ApplePayAvailabilityResult` [Section titled “ApplePayAvailabilityResult”](#applepayavailabilityresult) ```typescript export interface ApplePayAvailabilityResult { /** * Indicates whether the device can make Apple Pay payments in general. */ canMakePayments: boolean; /** * Indicates whether the device can make Apple Pay payments with the supplied networks. */ canMakePaymentsUsingNetworks: boolean; } ``` ### `GooglePayAvailabilityResult` [Section titled “GooglePayAvailabilityResult”](#googlepayavailabilityresult) ```typescript export interface GooglePayAvailabilityResult { /** * Whether the user is able to provide payment information through the Google Pay payment sheet. */ isReady: boolean; /** * The current user's ability to pay with one or more of the payment methods specified in `IsReadyToPayRequest.allowedPaymentMethods`. * * This property only exists if `IsReadyToPayRequest.existingPaymentMethodRequired` was set to `true`. The property value will always be `true` if the request is configured for a test environment. */ paymentMethodPresent: boolean | undefined; } ``` ### `ApplePayPaymentOptions` [Section titled “ApplePayPaymentOptions”](#applepaypaymentoptions) ```typescript export interface ApplePayPaymentOptions { /** * Merchant identifier created in the Apple Developer portal. */ merchantIdentifier: string; /** * Two-letter ISO 3166 country code. */ countryCode: string; /** * Three-letter ISO 4217 currency code. */ currencyCode: string; /** * Payment summary items displayed in the Apple Pay sheet. */ paymentSummaryItems: ApplePaySummaryItem[]; /** * Card networks to support. */ supportedNetworks: ApplePayNetwork[]; /** * Merchant payment capabilities. Defaults to ['3DS'] when omitted. */ merchantCapabilities?: ApplePayMerchantCapability[]; /** * Contact fields that must be supplied for shipping. */ requiredShippingContactFields?: ApplePayContactField[]; /** * Contact fields that must be supplied for billing. */ requiredBillingContactFields?: ApplePayContactField[]; /** * Controls the shipping flow presented to the user. */ shippingType?: ApplePayShippingType; /** * Optional ISO 3166 country codes where the merchant is supported. */ supportedCountries?: string[]; /** * Optional opaque application data passed back in the payment token. */ applicationData?: string; /** * Recurring payment configuration (iOS 16+). */ recurringPaymentRequest?: ApplePayRecurringPaymentRequest; } ``` ### `GooglePayPaymentOptions` [Section titled “GooglePayPaymentOptions”](#googlepaypaymentoptions) ```typescript export interface GooglePayPaymentOptions { /** * Environment used to construct the Google Payments client. Defaults to `'test'`. */ environment?: GooglePayEnvironment; /** * Raw `PaymentDataRequest` JSON as defined by the Google Pay API. * Provide transaction details, merchant info, and tokenization parameters. * * @see https://developers.google.com/pay/api/android/reference/request-objects#PaymentDataRequest */ paymentDataRequest: GooglePayPaymentDataRequest; } ``` ### `ApplePayRequestPaymentResult` [Section titled “ApplePayRequestPaymentResult”](#applepayrequestpaymentresult) ```typescript export interface ApplePayRequestPaymentResult { /** * Platform that resolved the payment request. */ platform: 'ios'; /** * Apple Pay payment payload. */ apple: ApplePayPaymentResult; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-pdf-generator > Generate PDF files from HTML strings or URLs on iOS and Android. ## Overview [Section titled “Overview”](#overview) Generate PDF files from HTML strings or URLs on iOS and Android. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `fromURL` - Generates a PDF from the provided URL. * `fromData` - Generates a PDF from a raw HTML string. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------ | ---------------------------------------- | | `fromURL` | Generates a PDF from the provided URL. | | `fromData` | Generates a PDF from a raw HTML string. | | `getPluginVersion` | Get the native Capacitor plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-pdf-generator](https://github.com/Cap-go/capacitor-pdf-generator/). # Getting Started > Install @capgo/capacitor-pdf-generator and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-pdf-generator bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { PdfGenerator } from '@capgo/capacitor-pdf-generator'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `fromURL` [Section titled “fromURL”](#fromurl) Generates a PDF from the provided URL. ```typescript import { PdfGenerator } from '@capgo/capacitor-pdf-generator'; await PdfGenerator.fromURL({} as PdfGeneratorFromUrlOptions); ``` ### `fromData` [Section titled “fromData”](#fromdata) Generates a PDF from a raw HTML string. ```typescript import { PdfGenerator } from '@capgo/capacitor-pdf-generator'; await PdfGenerator.fromData({} as PdfGeneratorFromDataOptions); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `PdfGeneratorFromUrlOptions` [Section titled “PdfGeneratorFromUrlOptions”](#pdfgeneratorfromurloptions) ```typescript export interface PdfGeneratorFromUrlOptions extends PdfGeneratorCommonOptions { url: string; } ``` ### `PdfGeneratorResult` [Section titled “PdfGeneratorResult”](#pdfgeneratorresult) ```typescript export type PdfGeneratorResult = | { type: 'base64'; base64: string; } | { type: 'share'; completed: boolean; }; ``` ### `PdfGeneratorFromDataOptions` [Section titled “PdfGeneratorFromDataOptions”](#pdfgeneratorfromdataoptions) ```typescript export interface PdfGeneratorFromDataOptions extends PdfGeneratorCommonOptions { /** * HTML document to render. */ data: string; /** * Base URL to use when resolving relative resources inside the HTML string. * When omitted, `about:blank` is used. */ baseUrl?: string; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-pedometer > Capacitor plugin for accessing pedometer data including steps, distance, pace, cadence, and floors. ## Overview [Section titled “Overview”](#overview) Capacitor plugin for accessing pedometer data including steps, distance, pace, cadence, and floors. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `getMeasurement` - Get pedometer measurements for a specified time range. * `isAvailable` - Check which pedometer features are available on this device. * `startMeasurementUpdates` - Start receiving real-time pedometer measurement updates. * `stopMeasurementUpdates` - Stop receiving real-time pedometer measurement updates. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------------- | ------------------------------------------------------------ | | `getMeasurement` | Get pedometer measurements for a specified time range. | | `isAvailable` | Check which pedometer features are available on this device. | | `startMeasurementUpdates` | Start receiving real-time pedometer measurement updates. | | `stopMeasurementUpdates` | Stop receiving real-time pedometer measurement updates. | | `checkPermissions` | Check permission to access pedometer data. | | `requestPermissions` | Request permission to access pedometer data. | | `addListener` | Called when a new pedometer measurement is received. | | `removeAllListeners` | Remove all listeners for this plugin. | | `getPluginVersion` | Get the native Capacitor plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-pedometer](https://github.com/Cap-go/capacitor-pedometer/). # Getting Started > Install @capgo/capacitor-pedometer and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-pedometer bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { CapacitorPedometer } from '@capgo/capacitor-pedometer'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `getMeasurement` [Section titled “getMeasurement”](#getmeasurement) Get pedometer measurements for a specified time range. ```typescript import { CapacitorPedometer } from '@capgo/capacitor-pedometer'; await CapacitorPedometer.getMeasurement(); ``` ### `isAvailable` [Section titled “isAvailable”](#isavailable) Check which pedometer features are available on this device. ```typescript import { CapacitorPedometer } from '@capgo/capacitor-pedometer'; await CapacitorPedometer.isAvailable(); ``` ### `startMeasurementUpdates` [Section titled “startMeasurementUpdates”](#startmeasurementupdates) Start receiving real-time pedometer measurement updates. On **Android** and **iOS**, the `measurement` event is only fired after calling `startMeasurementUpdates()`. ```typescript import { CapacitorPedometer } from '@capgo/capacitor-pedometer'; await CapacitorPedometer.startMeasurementUpdates(); ``` ### `stopMeasurementUpdates` [Section titled “stopMeasurementUpdates”](#stopmeasurementupdates) Stop receiving real-time pedometer measurement updates. ```typescript import { CapacitorPedometer } from '@capgo/capacitor-pedometer'; await CapacitorPedometer.stopMeasurementUpdates(); ``` ### `checkPermissions` [Section titled “checkPermissions”](#checkpermissions) Check permission to access pedometer data. On **Android**, this checks the `ACTIVITY_RECOGNITION` permission. On **iOS**, this checks the motion usage permission. ```typescript import { CapacitorPedometer } from '@capgo/capacitor-pedometer'; await CapacitorPedometer.checkPermissions(); ``` ### `requestPermissions` [Section titled “requestPermissions”](#requestpermissions) Request permission to access pedometer data. On **Android**, this requests the `ACTIVITY_RECOGNITION` permission. On **iOS**, this requests motion usage permission. ```typescript import { CapacitorPedometer } from '@capgo/capacitor-pedometer'; await CapacitorPedometer.requestPermissions(); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `GetMeasurementOptions` [Section titled “GetMeasurementOptions”](#getmeasurementoptions) ```typescript export interface GetMeasurementOptions { /** * The start time for the measurement query (milliseconds since epoch). * * Required on **iOS**. * * @since 0.0.1 */ start?: number; /** * The end time for the measurement query (milliseconds since epoch). * * Required on **iOS**. * * @since 0.0.1 */ end?: number; } ``` ### `Measurement` [Section titled “Measurement”](#measurement) ```typescript export interface Measurement { /** * The number of steps taken by the user. * * @since 0.0.1 */ numberOfSteps?: number; /** * The estimated distance (in meters) traveled by the user. * * Only available on **iOS**. * * @since 0.0.1 */ distance?: number; /** * The approximate number of floors ascended. * * Only available on **iOS**. * * @since 0.0.1 */ floorsAscended?: number; /** * The approximate number of floors descended. * * Only available on **iOS**. * * @since 0.0.1 */ floorsDescended?: number; /** * The current pace (in seconds per meter). * * Only available on **iOS**. * * @since 0.0.1 */ currentPace?: number; /** * The current cadence (steps per second). * * Only available on **iOS**. * * @since 0.0.1 */ currentCadence?: number; /** * The average active pace (in seconds per meter). * * Only available on **iOS**. * * @since 0.0.1 */ averageActivePace?: number; /** * The start time of this measurement (milliseconds since epoch). * * @since 0.0.1 */ startDate?: number; /** * The end time of this measurement (milliseconds since epoch). * * @since 0.0.1 */ endDate?: number; } ``` ### `IsAvailableResult` [Section titled “IsAvailableResult”](#isavailableresult) ```typescript export interface IsAvailableResult { /** * Whether step counting is available. * * @since 0.0.1 */ stepCounting: boolean; /** * Whether distance measurement is available. * * Only `true` on **iOS** devices that support distance tracking. * * @since 0.0.1 */ distance: boolean; /** * Whether pace measurement is available. * * Only `true` on **iOS** devices that support pace tracking. * * @since 0.0.1 */ pace: boolean; /** * Whether cadence measurement is available. * * Only `true` on **iOS** devices that support cadence tracking. * * @since 0.0.1 */ cadence: boolean; /** * Whether floor counting is available. * * Only `true` on **iOS** devices that support floor tracking. * * @since 0.0.1 */ floorCounting: boolean; } ``` ### `PermissionStatus` [Section titled “PermissionStatus”](#permissionstatus) ```typescript export interface PermissionStatus { /** * Permission state for activity recognition. * * On **Android**, this is the `ACTIVITY_RECOGNITION` permission. * On **iOS**, this is the motion usage permission. * * @since 0.0.1 */ activityRecognition: 'prompt' | 'prompt-with-rationale' | 'granted' | 'denied'; } ``` ### `MeasurementEvent` [Section titled “MeasurementEvent”](#measurementevent) ```typescript export type MeasurementEvent = Measurement; ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-persistent-account > Capacitor Persistent Account Plugin. ## Overview [Section titled “Overview”](#overview) Capacitor Persistent Account Plugin. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `readAccount` - Reads the stored account data from persistent storage. * `saveAccount` - Saves account data to persistent storage. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------ | ------------------------------------------------------ | | `readAccount` | Reads the stored account data from persistent storage. | | `saveAccount` | Saves account data to persistent storage. | | `getPluginVersion` | Get the native Capacitor plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-persistent-account](https://github.com/Cap-go/capacitor-persistent-account/). # Getting Started > Install @capgo/capacitor-persistent-account and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-persistent-account bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { CapacitorPersistentAccount } from '@capgo/capacitor-persistent-account'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `readAccount` [Section titled “readAccount”](#readaccount) Reads the stored account data from persistent storage. Retrieves account data that was previously saved using saveAccount(). The data persists across app sessions and survives app reinstallation on supported platforms. ```typescript import { CapacitorPersistentAccount } from '@capgo/capacitor-persistent-account'; const result = await CapacitorPersistentAccount.readAccount(); if (result.data) { console.log('Account data:', result.data); } else { console.log('No account data found'); } ``` ### `saveAccount` [Section titled “saveAccount”](#saveaccount) Saves account data to persistent storage. Stores the provided account data using platform-specific secure storage mechanisms. The data will persist across app sessions and survive app reinstallation. Any existing account data will be overwritten. ```typescript import { CapacitorPersistentAccount } from '@capgo/capacitor-persistent-account'; await CapacitorPersistentAccount.saveAccount({ data: { userId: '12345', username: 'john.doe', email: 'john@example.com' } }); ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-intune > Capacitor plugin for Microsoft Intune MAM enrollment, app protection policies, app config, and MSAL authentication. ## Overview [Section titled “Overview”](#overview) Capacitor plugin for Microsoft Intune MAM enrollment, app protection policies, app config, and MSAL authentication. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `acquireToken` - Present the Microsoft sign-in flow and return an access token plus the account metadata. * `acquireTokenSilent` - Acquire a token from the MSAL cache for a previously signed-in user. * `registerAndEnrollAccount` - Register a previously authenticated account with Intune and start enrollment. * `loginAndEnrollAccount` - Ask Intune to authenticate and enroll a user without first requesting an app token. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------------------ | ---------------------------------------------------------------------------------------- | | `acquireToken` | Present the Microsoft sign-in flow and return an access token plus the account metadata. | | `acquireTokenSilent` | Acquire a token from the MSAL cache for a previously signed-in user. | | `registerAndEnrollAccount` | Register a previously authenticated account with Intune and start enrollment. | | `loginAndEnrollAccount` | Ask Intune to authenticate and enroll a user without first requesting an app token. | | `enrolledAccount` | Return the currently enrolled Intune account, if one is available. | | `deRegisterAndUnenrollAccount` | Deregister the account from Intune and trigger selective wipe when applicable. | | `logoutOfAccount` | Sign the user out of MSAL without unenrolling the Intune account. | | `appConfig` | Fetch the remote Intune app configuration for a managed account. | | `getPolicy` | Fetch the currently effective Intune app protection policy for a managed account. | | `groupName` | Convenience helper that resolves the `GroupName` app configuration value when present. | | `sdkVersion` | Return the native Intune and MSAL SDK versions bundled by this plugin. | | `displayDiagnosticConsole` | Show the native Intune diagnostics UI. | | `addListener` | Listen for remote app configuration refreshes. | | `addListener` | Listen for remote app protection policy refreshes. | | `removeAllListeners` | Remove all registered listeners for this plugin instance. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-persona](https://github.com/Cap-go/capacitor-persona/). # Getting Started > Install @capgo/capacitor-intune and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-intune bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { IntuneMAM } from '@capgo/capacitor-intune'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `acquireToken` [Section titled “acquireToken”](#acquiretoken) Present the Microsoft sign-in flow and return an access token plus the account metadata. ```typescript import { IntuneMAM } from '@capgo/capacitor-intune'; await IntuneMAM.acquireToken({} as AcquireTokenOptions); ``` ### `acquireTokenSilent` [Section titled “acquireTokenSilent”](#acquiretokensilent) Acquire a token from the MSAL cache for a previously signed-in user. ```typescript import { IntuneMAM } from '@capgo/capacitor-intune'; await IntuneMAM.acquireTokenSilent({} as AcquireTokenSilentOptions); ``` ### `registerAndEnrollAccount` [Section titled “registerAndEnrollAccount”](#registerandenrollaccount) Register a previously authenticated account with Intune and start enrollment. ```typescript import { IntuneMAM } from '@capgo/capacitor-intune'; await IntuneMAM.registerAndEnrollAccount({} as RegisterAndEnrollAccountOptions); ``` ### `loginAndEnrollAccount` [Section titled “loginAndEnrollAccount”](#loginandenrollaccount) Ask Intune to authenticate and enroll a user without first requesting an app token. ```typescript import { IntuneMAM } from '@capgo/capacitor-intune'; await IntuneMAM.loginAndEnrollAccount(); ``` ### `enrolledAccount` [Section titled “enrolledAccount”](#enrolledaccount) Return the currently enrolled Intune account, if one is available. ```typescript import { IntuneMAM } from '@capgo/capacitor-intune'; await IntuneMAM.enrolledAccount(); ``` ### `deRegisterAndUnenrollAccount` [Section titled “deRegisterAndUnenrollAccount”](#deregisterandunenrollaccount) Deregister the account from Intune and trigger selective wipe when applicable. ```typescript import { IntuneMAM } from '@capgo/capacitor-intune'; await IntuneMAM.deRegisterAndUnenrollAccount({} as IntuneMAMUser); ``` ### `logoutOfAccount` [Section titled “logoutOfAccount”](#logoutofaccount) Sign the user out of MSAL without unenrolling the Intune account. ```typescript import { IntuneMAM } from '@capgo/capacitor-intune'; await IntuneMAM.logoutOfAccount({} as IntuneMAMUser); ``` ### `appConfig` [Section titled “appConfig”](#appconfig) Fetch the remote Intune app configuration for a managed account. ```typescript import { IntuneMAM } from '@capgo/capacitor-intune'; await IntuneMAM.appConfig({} as IntuneMAMUser); ``` ### `getPolicy` [Section titled “getPolicy”](#getpolicy) Fetch the currently effective Intune app protection policy for a managed account. ```typescript import { IntuneMAM } from '@capgo/capacitor-intune'; await IntuneMAM.getPolicy({} as IntuneMAMUser); ``` ### `groupName` [Section titled “groupName”](#groupname) Convenience helper that resolves the `GroupName` app configuration value when present. ```typescript import { IntuneMAM } from '@capgo/capacitor-intune'; await IntuneMAM.groupName({} as IntuneMAMUser); ``` ### `sdkVersion` [Section titled “sdkVersion”](#sdkversion) Return the native Intune and MSAL SDK versions bundled by this plugin. ```typescript import { IntuneMAM } from '@capgo/capacitor-intune'; await IntuneMAM.sdkVersion(); ``` ### `displayDiagnosticConsole` [Section titled “displayDiagnosticConsole”](#displaydiagnosticconsole) Show the native Intune diagnostics UI. ```typescript import { IntuneMAM } from '@capgo/capacitor-intune'; await IntuneMAM.displayDiagnosticConsole(); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `AcquireTokenOptions` [Section titled “AcquireTokenOptions”](#acquiretokenoptions) Interactive token acquisition options. ```typescript export interface AcquireTokenOptions { /** * Scopes to request, for example `https://graph.microsoft.com/.default`. */ scopes: string[]; /** * When true, always show the Microsoft account picker or sign-in UI. * * @default false */ forcePrompt?: boolean; /** * Optional login hint for the interactive sign-in flow. */ loginHint?: string; } ``` ### `IntuneMAMAcquireToken` [Section titled “IntuneMAMAcquireToken”](#intunemamacquiretoken) ```typescript export interface IntuneMAMAcquireToken { accountId: string; accessToken: string; accountIdentifier: string; idToken?: string; username?: string; tenantId?: string; authority?: string; } ``` ### `AcquireTokenSilentOptions` [Section titled “AcquireTokenSilentOptions”](#acquiretokensilentoptions) Silent token acquisition options. ```typescript export interface AcquireTokenSilentOptions { /** * Scopes to request, for example `https://graph.microsoft.com/.default`. */ scopes: string[]; /** * Microsoft Entra object ID returned by `acquireToken` or `enrolledAccount`. */ accountId: string; /** * When true, bypass the cached access token and request a fresh one. * * @default false */ forceRefresh?: boolean; } ``` ### `RegisterAndEnrollAccountOptions` [Section titled “RegisterAndEnrollAccountOptions”](#registerandenrollaccountoptions) ```typescript export interface RegisterAndEnrollAccountOptions { /** * Microsoft Entra object ID returned by `acquireToken`. */ accountId: string; } ``` ### `IntuneMAMUser` [Section titled “IntuneMAMUser”](#intunemamuser) ```typescript export interface IntuneMAMUser { accountId: string; accountIdentifier?: string; username?: string; tenantId?: string; authority?: string; } ``` ### `IntuneMAMAppConfig` [Section titled “IntuneMAMAppConfig”](#intunemamappconfig) ```typescript export interface IntuneMAMAppConfig { accountId: string; fullData: Record<string, string>[]; values: Record<string, string>; conflicts: string[]; } ``` ### `IntuneMAMPolicy` [Section titled “IntuneMAMPolicy”](#intunemampolicy) ```typescript export interface IntuneMAMPolicy { accountId: string; isPinRequired?: boolean; isManagedBrowserRequired?: boolean; isScreenCaptureAllowed?: boolean; isContactSyncAllowed?: boolean; isAppSharingAllowed?: boolean; isFileEncryptionRequired?: boolean; notificationPolicy?: string; } ``` ### `IntuneMAMGroupName` [Section titled “IntuneMAMGroupName”](#intunemamgroupname) ```typescript export interface IntuneMAMGroupName { accountId: string; groupName?: string; } ``` ### `IntuneMAMVersionInfo` [Section titled “IntuneMAMVersionInfo”](#intunemamversioninfo) ```typescript export interface IntuneMAMVersionInfo { platform: 'ios' | 'android'; intuneSdkVersion: string; msalVersion?: string; } ``` ### `IntuneMAMChangeEvent` [Section titled “IntuneMAMChangeEvent”](#intunemamchangeevent) ```typescript export interface IntuneMAMChangeEvent { accountId?: string; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-photo-library > Capacitor plugin Displays photo gallery as web page, or boring native screen which you cannot modify but require no authorization. ## Overview [Section titled “Overview”](#overview) Capacitor plugin Displays photo gallery as web page, or boring native screen which you cannot modify but require no authorization. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `checkAuthorization` - Returns the current authorization status without prompting the user. * `requestAuthorization` - Requests access to the photo library if needed. * `getAlbums` - Retrieves the available albums. * `getLibrary` - Retrieves library assets along with URLs that can be displayed in the web view. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `checkAuthorization` | Returns the current authorization status without prompting the user. | | `requestAuthorization` | Requests access to the photo library if needed. | | `getAlbums` | Retrieves the available albums. | | `getLibrary` | Retrieves library assets along with URLs that can be displayed in the web view. | | `getPhotoUrl` | Retrieves a displayable URL for the full resolution version of the asset. If you already called `getLibrary` with `includeFullResolutionData`, you normally do not need this method. | | `getThumbnailUrl` | Retrieves a displayable URL for a resized thumbnail of the asset. | | `pickMedia` | Opens the native system picker so the user can select media without granting full photo library access. The selected files are copied into the application cache and returned with portable URLs. | | `getPluginVersion` | Get the native Capacitor plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-photo-library](https://github.com/Cap-go/capacitor-photo-library/). # Getting Started > Install @capgo/capacitor-photo-library and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-photo-library bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { PhotoLibrary } from '@capgo/capacitor-photo-library'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `checkAuthorization` [Section titled “checkAuthorization”](#checkauthorization) Returns the current authorization status without prompting the user. ```typescript import { PhotoLibrary } from '@capgo/capacitor-photo-library'; await PhotoLibrary.checkAuthorization(); ``` ### `requestAuthorization` [Section titled “requestAuthorization”](#requestauthorization) Requests access to the photo library if needed. ```typescript import { PhotoLibrary } from '@capgo/capacitor-photo-library'; await PhotoLibrary.requestAuthorization(); ``` ### `getAlbums` [Section titled “getAlbums”](#getalbums) Retrieves the available albums. ```typescript import { PhotoLibrary } from '@capgo/capacitor-photo-library'; await PhotoLibrary.getAlbums(); ``` ### `getLibrary` [Section titled “getLibrary”](#getlibrary) Retrieves library assets along with URLs that can be displayed in the web view. ```typescript import { PhotoLibrary } from '@capgo/capacitor-photo-library'; await PhotoLibrary.getLibrary(); ``` ### `getPhotoUrl` [Section titled “getPhotoUrl”](#getphotourl) Retrieves a displayable URL for the full resolution version of the asset. If you already called `getLibrary` with `includeFullResolutionData`, you normally do not need this method. ```typescript import { PhotoLibrary } from '@capgo/capacitor-photo-library'; await PhotoLibrary.getPhotoUrl({} as { id: string }); ``` ### `getThumbnailUrl` [Section titled “getThumbnailUrl”](#getthumbnailurl) Retrieves a displayable URL for a resized thumbnail of the asset. ```typescript import { PhotoLibrary } from '@capgo/capacitor-photo-library'; await PhotoLibrary.getThumbnailUrl({} as { id: string; width?: number; height?: number; quality?: number; }); ``` ### `pickMedia` [Section titled “pickMedia”](#pickmedia) Opens the native system picker so the user can select media without granting full photo library access. The selected files are copied into the application cache and returned with portable URLs. ```typescript import { PhotoLibrary } from '@capgo/capacitor-photo-library'; await PhotoLibrary.pickMedia(); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `PhotoLibraryAuthorizationState` [Section titled “PhotoLibraryAuthorizationState”](#photolibraryauthorizationstate) ```typescript export type PhotoLibraryAuthorizationState = 'authorized' | 'limited' | 'denied' | 'notDetermined'; ``` ### `PhotoLibraryAlbum` [Section titled “PhotoLibraryAlbum”](#photolibraryalbum) ```typescript export interface PhotoLibraryAlbum { id: string; title: string; assetCount: number; } ``` ### `GetLibraryOptions` [Section titled “GetLibraryOptions”](#getlibraryoptions) ```typescript export interface GetLibraryOptions { /** * Number of assets to skip from the beginning of the query. */ offset?: number; /** * Maximum number of assets to return. Omit to return everything that matches. */ limit?: number; /** * Include images in the result. Defaults to `true`. */ includeImages?: boolean; /** * Include videos in the result. Defaults to `false`. */ includeVideos?: boolean; /** * Include information about the albums each asset belongs to. Defaults to `false`. */ includeAlbumData?: boolean; /** * Include assets stored in the cloud (iCloud / Google Photos). Defaults to `true`. */ includeCloudData?: boolean; /** * If `true`, use the original filenames reported by the OS when available. */ useOriginalFileNames?: boolean; /** * Width of the generated thumbnails. Defaults to `512`. */ thumbnailWidth?: number; /** * Height of the generated thumbnails. Defaults to `384`. */ thumbnailHeight?: number; /** * JPEG quality for generated thumbnails (0-1). Defaults to `0.5`. */ thumbnailQuality?: number; /** * When `true`, copies the full sized asset into the app cache and returns its URL. * Defaults to `false`. */ includeFullResolutionData?: boolean; } ``` ### `GetLibraryResult` [Section titled “GetLibraryResult”](#getlibraryresult) ```typescript export interface GetLibraryResult { assets: PhotoLibraryAsset[]; /** * Total number of assets matching the query in the library. `assets.length` can be less * than this value when pagination is used. */ totalCount: number; /** Whether more assets are available when using pagination. */ hasMore: boolean; } ``` ### `PhotoLibraryFile` [Section titled “PhotoLibraryFile”](#photolibraryfile) ```typescript export interface PhotoLibraryFile { /** Absolute path on the native file system. */ path: string; /** * URL that can be used inside a web view. Usually produced by `Capacitor.convertFileSrc(path)`. */ webPath: string; mimeType: string; /** Size in bytes if known, otherwise `-1`. */ size: number; } ``` ### `PickMediaOptions` [Section titled “PickMediaOptions”](#pickmediaoptions) ```typescript export interface PickMediaOptions { /** * Maximum number of items the user can select. Use `0` to allow unlimited selection. * Defaults to `1`. */ selectionLimit?: number; /** Allow the user to select images. Defaults to `true`. */ includeImages?: boolean; /** Allow the user to select videos. Defaults to `false`. */ includeVideos?: boolean; /** Width of the generated thumbnails for picked items. Defaults to `256`. */ thumbnailWidth?: number; /** Height of the generated thumbnails for picked items. Defaults to `256`. */ thumbnailHeight?: number; /** JPEG quality for generated thumbnails (0-1). Defaults to `0.7`. */ thumbnailQuality?: number; } ``` ### `PickMediaResult` [Section titled “PickMediaResult”](#pickmediaresult) ```typescript export interface PickMediaResult { assets: PhotoLibraryAsset[]; } ``` ### `PhotoLibraryAsset` [Section titled “PhotoLibraryAsset”](#photolibraryasset) ```typescript export interface PhotoLibraryAsset { id: string; fileName: string; type: PhotoAssetType; width: number; height: number; duration?: number; creationDate?: string; modificationDate?: string; latitude?: number; longitude?: number; mimeType: string; /** Size in bytes reported by the OS for the underlying asset, if available. */ size?: number; albumIds?: string[]; thumbnail?: PhotoLibraryFile; file?: PhotoLibraryFile; } ``` ### `PhotoAssetType` [Section titled “PhotoAssetType”](#photoassettype) ```typescript export type PhotoAssetType = 'image' | 'video'; ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-printer > Capacitor plugin for printing documents, HTML, PDFs, images and web views. ## Overview [Section titled “Overview”](#overview) Capacitor plugin for printing documents, HTML, PDFs, images and web views. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `printBase64` - Presents the printing UI to print files encoded as base64 strings. * `printFile` - Presents the printing UI to print device files. * `printHtml` - Presents the printing UI to print HTML documents. * `printPdf` - Presents the printing UI to print PDF documents. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------ | ------------------------------------------------------------------ | | `printBase64` | Presents the printing UI to print files encoded as base64 strings. | | `printFile` | Presents the printing UI to print device files. | | `printHtml` | Presents the printing UI to print HTML documents. | | `printPdf` | Presents the printing UI to print PDF documents. | | `printWebView` | Presents the printing UI to print web view content. | | `getPluginVersion` | Get the native Capacitor plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-printer](https://github.com/Cap-go/capacitor-printer/). # Getting Started > Install @capgo/capacitor-printer and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-printer bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { Printer } from '@capgo/capacitor-printer'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `printBase64` [Section titled “printBase64”](#printbase64) Presents the printing UI to print files encoded as base64 strings. **Platform Behavior:** * **iOS**: Uses UIPrintInteractionController with base64 decoded data * **Android**: Uses PrintManager with base64 decoded data * **Web**: Creates a blob from base64 data and opens print dialog **Performance Warning:** Large files can lead to app crashes due to memory constraints when decoding base64. For files larger than 5MB, it’s recommended to use printFile() instead. ```typescript import { Printer } from '@capgo/capacitor-printer'; // Print a base64 encoded PDF await Printer.printBase64({ name: 'Invoice #12345', data: 'base64-encoded-pdf-data', mimeType: 'application/pdf', }); // Print a base64 encoded image await Printer.printBase64({ name: 'Product Photo', data: '/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDA...', mimeType: 'image/jpeg', }); ``` ### `printFile` [Section titled “printFile”](#printfile) Presents the printing UI to print device files. **Platform Behavior:** * **iOS**: Uses UIPrintInteractionController with file URL. Supports file:// paths or paths relative to app’s documents directory. * **Android**: Uses PrintManager with file path. Supports both content:// URIs and file:// paths. * **Web**: Reads file and opens print dialog **Supported File Types:** * PDF documents (application/pdf) * Images: JPEG, PNG, GIF, HEIC, HEIF ```typescript import { Printer } from '@capgo/capacitor-printer'; // iOS: Print from app documents directory await Printer.printFile({ name: 'Contract', path: 'file:///var/mobile/Containers/Data/Application/.../Documents/contract.pdf', }); // Android: Print from content URI await Printer.printFile({ name: 'Receipt', path: 'content://com.android.providers.downloads.documents/document/123', mimeType: 'application/pdf', }); // Android: Print from file path await Printer.printFile({ name: 'Photo', path: 'file:///storage/emulated/0/Download/photo.jpg', mimeType: 'image/jpeg', }); ``` ### `printHtml` [Section titled “printHtml”](#printhtml) Presents the printing UI to print HTML documents. **Platform Behavior:** * **iOS**: Renders HTML in WKWebView, then prints using UIPrintInteractionController * **Android**: Renders HTML in WebView, then prints using PrintManager * **Web**: Creates iframe with HTML content and triggers print dialog **HTML Requirements:** * Should be a complete HTML document with proper structure * Can include inline CSS styles or style tags * External resources (images, stylesheets) should use absolute URLs * Print-specific CSS can be added using ```typescript import { Printer } from '@capgo/capacitor-printer'; // Simple HTML document await Printer.printHtml({ name: 'Sales Report', html: '<html><body><h1>Q4 Sales Report</h1><p>Revenue: $125,000</p></body></html>', }); // HTML with print-specific CSS await Printer.printHtml({ name: 'Styled Invoice', html: ` <html> <head> <style> ``` ### `printPdf` [Section titled “printPdf”](#printpdf) Presents the printing UI to print PDF documents. **Platform Behavior:** * **iOS**: Uses UIPrintInteractionController with PDF file URL * **Android**: Uses PrintManager with PdfDocument * **Web**: Creates object URL and opens print dialog **File Path Requirements:** * **iOS**: Must be file:// path or relative to app’s documents directory * **Android**: Supports content:// URIs (from downloads, media store) or file:// paths * **Web**: Must be accessible file path ```typescript import { Printer } from '@capgo/capacitor-printer'; // Print PDF from app storage await Printer.printPdf({ name: 'Annual Report 2024', path: 'file:///var/mobile/Containers/Data/Application/.../Documents/report.pdf', }); // Print PDF from Android downloads await Printer.printPdf({ name: 'Downloaded Document', path: 'content://com.android.providers.downloads.documents/document/123', }); ``` ### `printWebView` [Section titled “printWebView”](#printwebview) Presents the printing UI to print web view content. Prints the current content displayed in your app’s web view. **Platform Behavior:** * **iOS**: Uses UIPrintInteractionController with WKWebView’s view printable * **Android**: Uses WebView\.createPrintDocumentAdapter() with PrintManager * **Web**: Triggers window\.print() for current page **Print Styling:** Supports CSS print media queries for customization. The web view’s current styles will be applied, including any ```typescript import { Printer } from '@capgo/capacitor-printer'; // Print current web view with default name await Printer.printWebView(); // Print with custom job name await Printer.printWebView({ name: 'Dashboard Screenshot', }); // Use with print-specific CSS in your HTML // Add this to your app's CSS: // ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `PrintBase64Options` [Section titled “PrintBase64Options”](#printbase64options) Options for printing base64 encoded data. ```typescript export interface PrintBase64Options extends PrintOptions { /** * Valid base64 encoded string representing the file content. * * The base64 string should NOT include the data URL prefix (e.g., "data:application/pdf;base64,"). * Only provide the raw base64 encoded content. * * **Performance Considerations:** * - Base64 encoding increases data size by approximately 33% * - Large files (>5MB) may cause memory issues when decoding * - Consider using printFile() for large documents * * **Platform Notes:** * - **iOS**: Decoded to NSData and passed to UIPrintInteractionController * - **Android**: Decoded to byte array and written to temporary file * - **Web**: Converted to Blob for printing * * @since 7.0.0 * @example 'base64-encoded-pdf-data' */ data: string; /** * MIME type of the base64 encoded data. * * **Supported types:** * - `application/pdf` - PDF documents * - `image/jpeg` - JPEG images * - `image/.png` - PNG images * - `image/.gif` - GIF images (iOS/Android only) * - `image/heic` - HEIC images (iOS only) * - `image/heif` - HEIF images (iOS only) * * **Platform Support:** * - All platforms support PDF, JPEG, and PNG * - GIF support varies by platform * - HEIC/HEIF are iOS-specific formats * * @since 7.0.0 * @example 'application/pdf' * @example 'image/jpeg' */ mimeType: string; } ``` ### `PrintFileOptions` [Section titled “PrintFileOptions”](#printfileoptions) Options for printing files from device storage. ```typescript export interface PrintFileOptions extends PrintOptions { /** * Path to the file to print. * * **iOS Path Formats:** * - `file://` URL: Full file URL path * - Relative path: Path relative to app's documents directory * - Must be within app's accessible directories (documents, temporary, cache) * * **Android Path Formats:** * - `content://` URI: Content provider URI (recommended for external files) * - `file://` path: Direct file system path * - Must have read permission for the file * * **Common Use Cases:** * - App documents: Files saved in app's document directory * - Downloads: Files from system downloads folder (use content:// on Android) * - Temporary files: Files in app's temporary/cache directory * - Shared storage: Files from external storage (Android, requires permissions) * * @since 7.0.0 * @platform ios Supports file:// paths and relative paths * @platform android Supports content:// URIs and file:// paths * @example 'content://com.android.providers.downloads.documents/document/123' * @example 'file:///var/mobile/Containers/Data/Application/.../Documents/document.pdf' * @example 'file:///storage/emulated/0/Download/receipt.pdf' */ path: string; /** * MIME type of the file. * * **Platform Behavior:** * - **Android**: REQUIRED for content:// URIs. Helps the system determine how to handle the file. * Optional for file:// paths (auto-detected from extension). * - **iOS**: Ignored. File type is auto-detected from file extension. * - **Web**: Optional. Auto-detected if not provided. * * **Common MIME Types:** * - `application/pdf` - PDF documents * - `image/jpeg` - JPEG images * - `image/.png` - PNG images * - `image/.gif` - GIF images * * @since 7.0.0 * @default Undefined (auto-detected from file extension) * @platform android Used for content:// URIs and file type detection * @platform ios Ignored (auto-detected) * @example 'application/pdf' * @example 'image/jpeg' */ mimeType?: string; } ``` ### `PrintHtmlOptions` [Section titled “PrintHtmlOptions”](#printhtmloptions) Options for printing HTML content. ````typescript export interface PrintHtmlOptions extends PrintOptions { /** * HTML content to print. * * **Content Requirements:** * - Should be a complete HTML document with `<html>`, `<head>`, and `<body>` tags * - Can include inline CSS styles or `<style>` tags * - External resources (images, fonts) should use absolute URLs * - JavaScript is not executed during print rendering * * **Print Optimization Tips:** * - Use `@media print` CSS rules for print-specific styling * - Control page breaks with `page-break-before`, `page-break-after`, `page-break-inside` * - Hide UI elements using `.no-print { display: none; }` class * - Adjust font sizes for readability (12pt is standard for print) * - Use print-friendly colors (avoid dark backgrounds) * * **Platform Rendering:** * - **iOS**: Rendered in WKWebView before printing * - **Android**: Rendered in WebView before printing * - **Web**: Rendered in hidden iframe before printing * * **Character Encoding:** * - UTF-8 is recommended and default * - Include charset in HTML: `<meta charset="UTF-8">` * * @since 7.0.0 * @example '<html><body><h1>Hello World</h1><p>This is a test document.</p></body></html>' * @example * ```typescript * const htmlWithStyles = ` * <html> * <head> * <meta charset="UTF-8"> * <style> * @media print { * body { font-family: Arial, sans-serif; font-size: 12pt; } * .no-print { display: none; } * h1 { color: #333; page-break-before: always; } * } * </style> * </head> * <body> * <h1>Invoice #12345</h1> * <p>Amount: $299.99</p> * </body> * </html> * `; * ``` */ html: string; } ```` ### `PrintPdfOptions` [Section titled “PrintPdfOptions”](#printpdfoptions) Options for printing PDF documents. ```typescript export interface PrintPdfOptions extends PrintOptions { /** * Path to the PDF document. * * **iOS Path Formats:** * - `file://` URL: Full file URL path to PDF document * - Relative path: Path relative to app's documents directory * - Must be within app's accessible directories (documents, temporary, cache) * - PDF must be valid and not password-protected * * **Android Path Formats:** * - `content://` URI: Content provider URI (recommended for external PDFs) * - `file://` path: Direct file system path to PDF * - Must have read permission for the file * - Supports both single-page and multi-page PDFs * * **Web Path Formats:** * - Relative or absolute path accessible from web context * - Must be a valid PDF file * * **Validation:** * - File must exist at the specified path * - File must be a valid PDF (checked by magic number/header) * - File must be readable by the app * * **Common Sources:** * - App documents: PDFs saved in app's document directory * - Downloads: PDFs from system downloads (use content:// on Android) * - Generated PDFs: Temporary PDFs created by the app * - Network downloads: PDFs downloaded and saved locally * * @since 7.0.0 * @platform ios Supports file:// paths and relative paths * @platform android Supports content:// URIs and file:// paths * @platform web Supports accessible file paths * @example 'content://com.android.providers.downloads.documents/document/123' * @example 'file:///var/mobile/Containers/Data/Application/.../Documents/document.pdf' * @example 'file:///storage/emulated/0/Download/report.pdf' * @example 'Documents/invoice-2024.pdf' */ path: string; } ``` ### `PrintOptions` [Section titled “PrintOptions”](#printoptions) Base options for all print operations. ```typescript export interface PrintOptions { /** * Name of the print job. * * **Usage:** * - Displayed in the system print queue * - Shown in print history/logs * - May appear in printer status displays * - Used as default filename for "Save as PDF" option * * **Platform Behavior:** * - **iOS**: Shown in print preview header and activity view * - **Android**: Displayed in print job notification and print queue * - **Web**: Used as document title in print dialog * * **Best Practices:** * - Use descriptive names (e.g., "Invoice #12345", "Q4 Report") * - Keep under 50 characters for better display * - Avoid special characters that may cause issues in filenames * - Include relevant identifiers (order numbers, dates, etc.) * * **Examples:** * - "Invoice #12345" * - "Sales Report - 2024 Q4" * - "Customer Receipt - John Doe" * - "Product Photo - SKU-ABC123" * * @since 7.0.0 * @default 'Document' * @platform ios Shown in print preview and activity view * @platform android Shown in print queue and notifications * @platform web Used as document title in print dialog * @example 'Invoice #12345' * @example 'Annual Report 2024' * @example 'Receipt - Order #789' */ name?: string; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-privacy-screen > Capacitor API for protecting app content from the app switcher preview. ## Overview [Section titled “Overview”](#overview) Capacitor API for protecting app content from the app switcher preview. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `enable` - Enables the privacy screen. * `disable` - Disables the privacy screen. * `isEnabled` - Returns the current enabled state. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------ | ------------------------------------------------- | | `enable` | Enables the privacy screen. | | `disable` | Disables the privacy screen. | | `isEnabled` | Returns the current enabled state. | | `getPluginVersion` | Returns the native implementation version marker. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-privacy-screen](https://github.com/Cap-go/capacitor-privacy-screen/). # Android Behavior > Understand how Privacy Screen blocks screenshots, recordings, and recents previews on Android. ## How Android protection works [Section titled “How Android protection works”](#how-android-protection-works) On Android, the plugin applies `WindowManager.LayoutParams.FLAG_SECURE` to the activity window. That protects your app from: * screenshots * screen recordings in most normal capture paths * the recent apps thumbnail preview ## Setup [Section titled “Setup”](#setup) No extra Android manifest or Gradle configuration is required after installation and `cap sync`. ## Runtime control [Section titled “Runtime control”](#runtime-control) ```typescript import { PrivacyScreen } from '@capgo/capacitor-privacy-screen'; await PrivacyScreen.disable(); // Allow a temporary flow where capture is acceptable. await PrivacyScreen.enable(); ``` ## Important note [Section titled “Important note”](#important-note) `FLAG_SECURE` is an Android platform feature. If you disable the plugin, users and other apps can capture your content again until you re-enable it. # Getting Started > Install and control the Privacy Screen plugin for Capacitor apps on iOS and Android. 1. **Install the plugin** ```sh bun add @capgo/capacitor-privacy-screen ``` 2. **Sync native platforms** ```sh bunx cap sync ``` 3. **Review platform behavior** * Read the [iOS notes](/docs/plugins/privacy-screen/ios/) for app switcher behavior. * Read the [Android notes](/docs/plugins/privacy-screen/android/) for screenshot and recording behavior. ## Default behavior [Section titled “Default behavior”](#default-behavior) The plugin enables privacy protection automatically when the native implementation loads. * On Android, secure mode blocks screenshots, screen recording capture, and the recent apps preview. * On iOS, the plugin hides your app during app switcher snapshot generation. * On Web, the plugin keeps an in-memory enabled flag only for API parity. ## Basic usage [Section titled “Basic usage”](#basic-usage) ```typescript import { PrivacyScreen } from '@capgo/capacitor-privacy-screen'; await PrivacyScreen.disable(); // Run a flow where screenshots or previews are temporarily allowed. await PrivacyScreen.enable(); const { enabled } = await PrivacyScreen.isEnabled(); console.log('Privacy screen enabled:', enabled); ``` ## When to disable it temporarily [Section titled “When to disable it temporarily”](#when-to-disable-it-temporarily) Use `disable()` only when the current screen should remain visible in system previews or be capturable by the user, for example: * account verification steps that require screenshots for support * payment or identity-provider flows that need a visible app switcher preview * controlled debugging sessions on trusted devices Restore protection immediately afterward with `enable()`. # iOS Behavior > Understand how Privacy Screen protects your Capacitor app in the iOS app switcher. ## How iOS protection works [Section titled “How iOS protection works”](#how-ios-protection-works) On iOS, the plugin adds a temporary native overlay while the app resigns active. That overlay is what appears in the app switcher snapshot instead of your real interface. This means the plugin protects: * the app switcher preview * the snapshot iOS keeps when your app moves to the background ## What it does not do [Section titled “What it does not do”](#what-it-does-not-do) iOS does not offer the same screenshot blocking API as Android. The plugin cannot prevent a user from taking a screenshot while actively using the app. If you need stronger policy controls on iOS, combine this plugin with app-level choices such as: * masking especially sensitive UI before presenting it * minimizing sensitive data retention on screen * clearing temporary values when the app backgrounds ## Setup [Section titled “Setup”](#setup) No extra iOS configuration is required after installation and `cap sync`. ## Example flow [Section titled “Example flow”](#example-flow) ```typescript import { PrivacyScreen } from '@capgo/capacitor-privacy-screen'; await PrivacyScreen.enable(); ``` For most apps, even this explicit call is optional because the plugin starts enabled by default. # @capgo/capacitor-proximity > Enable native proximity monitoring so your app can react when the device is held to the ear, covered by a hand, or placed face down. ## Overview [Section titled “Overview”](#overview) Capacitor plugin for enabling proximity monitoring in mobile apps. Simple Control Turn proximity monitoring on when a flow starts and disable it cleanly when it ends. Native iOS Behavior Uses `UIDevice.isProximityMonitoringEnabled` so iOS handles the screen behavior natively. Android Sensor Support Listens to `Sensor.TYPE_PROXIMITY` and dims the current app window while the sensor is covered. Availability Checks Verify whether the current device exposes a usable proximity sensor before enabling the feature. Version Reporting Read the native plugin version at runtime for debugging, support, and diagnostics. Comprehensive Documentation Check the [Getting Started](/docs/plugins/proximity/getting-started/) guide to install and integrate the plugin quickly. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `enable` - Enable proximity monitoring. * `disable` - Disable proximity monitoring. * `getStatus` - Get the current sensor availability and plugin enabled state. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------ | ------------------------------------------------------------- | | `enable` | Enable proximity monitoring. | | `disable` | Disable proximity monitoring. | | `getStatus` | Get the current sensor availability and plugin enabled state. | | `getPluginVersion` | Get the current native plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-proximity](https://github.com/Cap-go/capacitor-proximity/). # Getting Started > Install @capgo/capacitor-proximity and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-proximity bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { CapacitorProximity } from '@capgo/capacitor-proximity'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `enable` [Section titled “enable”](#enable) Enable proximity monitoring. On iOS this enables `UIDevice.isProximityMonitoringEnabled`. On Android this starts listening to `TYPE_PROXIMITY` and dims the current app window while the sensor is covered. ```typescript import { CapacitorProximity } from '@capgo/capacitor-proximity'; await CapacitorProximity.enable(); ``` ### `disable` [Section titled “disable”](#disable) Disable proximity monitoring. This restores the default app window behavior and stops sensor monitoring. ```typescript import { CapacitorProximity } from '@capgo/capacitor-proximity'; await CapacitorProximity.disable(); ``` ### `getStatus` [Section titled “getStatus”](#getstatus) Get the current sensor availability and plugin enabled state. ```typescript import { CapacitorProximity } from '@capgo/capacitor-proximity'; const status = await CapacitorProximity.getStatus(); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `ProximityStatusResult` [Section titled “ProximityStatusResult”](#proximitystatusresult) Result returned by `getStatus()`. ```typescript export interface ProximityStatusResult { /** * Whether the current device exposes a usable proximity sensor. * * @since 0.0.1 */ available: boolean; /** * Whether proximity monitoring is currently enabled by the plugin. * * @since 0.0.1 */ enabled: boolean; /** * Platform label returned by the native or web implementation. * * @since 0.0.1 */ platform: 'ios' | 'android' | 'web'; } ``` ### `PluginVersionResult` [Section titled “PluginVersionResult”](#pluginversionresult) Result returned when requesting the plugin version. ```typescript export interface PluginVersionResult { /** * Native plugin version string. * * @since 0.0.1 */ version: string; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-realtimekit > Capacitor RealtimeKit Plugin for Cloudflare Calls integration. ## Overview [Section titled “Overview”](#overview) Capacitor RealtimeKit Plugin for Cloudflare Calls integration. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `initialize` - Initializes the RealtimeKit plugin before using other methods. * `startMeeting` - Start a meeting using the built-in UI. Only available on Android and iOS. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------ | ------------------------------------------------------------------------- | | `initialize` | Initializes the RealtimeKit plugin before using other methods. | | `startMeeting` | Start a meeting using the built-in UI. Only available on Android and iOS. | | `getPluginVersion` | Get the native Capacitor plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-realtimekit](https://github.com/Cap-go/capacitor-realtimekit/). # Getting Started > Install @capgo/capacitor-realtimekit and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-realtimekit bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { CapacitorRealtimekit } from '@capgo/capacitor-realtimekit'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `initialize` [Section titled “initialize”](#initialize) Initializes the RealtimeKit plugin before using other methods. ```typescript import { CapacitorRealtimekit } from '@capgo/capacitor-realtimekit'; await CapacitorRealtimekit.initialize(); ``` ### `startMeeting` [Section titled “startMeeting”](#startmeeting) Start a meeting using the built-in UI. Only available on Android and iOS. ```typescript import { CapacitorRealtimekit } from '@capgo/capacitor-realtimekit'; await CapacitorRealtimekit.startMeeting({ authToken: 'your-auth-token', enableAudio: true, enableVideo: true, }); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `StartMeetingOptions` [Section titled “StartMeetingOptions”](#startmeetingoptions) Configuration options for starting a meeting. ```typescript export interface StartMeetingOptions { /** * Authentication token for the participant. * This token is required to join the Cloudflare Calls meeting. * * @since 7.0.0 */ authToken: string; /** * Whether to join with audio enabled. * Default is true. * * @default true * @since 7.0.0 */ enableAudio?: boolean; /** * Whether to join with video enabled. * Default is true. * * @default true * @since 7.0.0 */ enableVideo?: boolean; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/ricoh360 > Provides an SDK for the Ricoh360 cameras for Capacitor. ## Overview [Section titled “Overview”](#overview) Provides an SDK for the Ricoh360 cameras for Capacitor. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `initialize` - Initializes the SDK with camera URL. * `getCameraAsset` - Retrieves a camera asset from a URL and returns it as base64. * `listFiles` - Lists files stored on the camera. * `capturePicture` - Captures a picture. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------ | ------------------------------------------------------------- | | `initialize` | Initializes the SDK with camera URL. | | `getCameraAsset` | Retrieves a camera asset from a URL and returns it as base64. | | `listFiles` | Lists files stored on the camera. | | `capturePicture` | Captures a picture. | | `captureVideo` | Captures a video. | | `livePreview` | Starts live preview. | | `stopLivePreview` | Stops live preview. | | `readSettings` | Reads camera settings. | | `setSettings` | Sets camera settings. | | `sendCommand` | Send raw command to camera. | | `getPluginVersion` | Get the native Capacitor plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-ricoh360-camera-plugin](https://github.com/Cap-go/capacitor-ricoh360-camera-plugin/). # Getting Started > Install @capgo/ricoh360 and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/ricoh360 bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { Ricoh360Camera } from '@capgo/ricoh360'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `initialize` [Section titled “initialize”](#initialize) Initializes the SDK with camera URL ```typescript import { Ricoh360Camera } from '@capgo/ricoh360'; await Ricoh360Camera.initialize({} as InitializeOptions); ``` ### `getCameraAsset` [Section titled “getCameraAsset”](#getcameraasset) Retrieves a camera asset from a URL and returns it as base64 ```typescript import { Ricoh360Camera } from '@capgo/ricoh360'; await Ricoh360Camera.getCameraAsset({} as GetCameraAssetOptions); ``` ### `listFiles` [Section titled “listFiles”](#listfiles) Lists files stored on the camera ```typescript import { Ricoh360Camera } from '@capgo/ricoh360'; await Ricoh360Camera.listFiles(); ``` ### `capturePicture` [Section titled “capturePicture”](#capturepicture) Captures a picture ```typescript import { Ricoh360Camera } from '@capgo/ricoh360'; await Ricoh360Camera.capturePicture(); ``` ### `captureVideo` [Section titled “captureVideo”](#capturevideo) Captures a video ```typescript import { Ricoh360Camera } from '@capgo/ricoh360'; await Ricoh360Camera.captureVideo({} as VideoCaptureOptions); ``` ### `livePreview` [Section titled “livePreview”](#livepreview) Starts live preview ```typescript import { Ricoh360Camera } from '@capgo/ricoh360'; await Ricoh360Camera.livePreview({} as LivePreviewOptions); ``` ### `stopLivePreview` [Section titled “stopLivePreview”](#stoplivepreview) Stops live preview ```typescript import { Ricoh360Camera } from '@capgo/ricoh360'; await Ricoh360Camera.stopLivePreview(); ``` ### `readSettings` [Section titled “readSettings”](#readsettings) Reads camera settings ```typescript import { Ricoh360Camera } from '@capgo/ricoh360'; await Ricoh360Camera.readSettings({} as { options: string[] }); ``` ### `setSettings` [Section titled “setSettings”](#setsettings) Sets camera settings ```typescript import { Ricoh360Camera } from '@capgo/ricoh360'; await Ricoh360Camera.setSettings({} as { options: Record<string, any> }); ``` ### `sendCommand` [Section titled “sendCommand”](#sendcommand) Send raw command to camera ```typescript import { Ricoh360Camera } from '@capgo/ricoh360'; await Ricoh360Camera.sendCommand({} as { endpoint: string; payload: Record<string, any> }); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `InitializeOptions` [Section titled “InitializeOptions”](#initializeoptions) ```typescript export interface InitializeOptions { url: string; } ``` ### `CommandResponse` [Section titled “CommandResponse”](#commandresponse) ```typescript export interface CommandResponse { session?: string; info?: string; preview?: string; picture?: string; settings?: string; } ``` ### `GetCameraAssetOptions` [Section titled “GetCameraAssetOptions”](#getcameraassetoptions) ```typescript export interface GetCameraAssetOptions { url: string; saveToFile?: boolean; } ``` ### `GetCameraAssetResponse` [Section titled “GetCameraAssetResponse”](#getcameraassetresponse) ```typescript export interface GetCameraAssetResponse { statusCode: number; data: string; // base64 encoded data filePath?: string; } ``` ### `ListFilesOptions` [Section titled “ListFilesOptions”](#listfilesoptions) ```typescript export interface ListFilesOptions { fileType?: 'all' | 'image' | 'video'; startPosition?: number; entryCount?: number; maxThumbSize?: number; _detail?: boolean; } ``` ### `ListFilesResponse` [Section titled “ListFilesResponse”](#listfilesresponse) ```typescript export interface ListFilesResponse { results: { entries: { name: string; fileUrl: string; size: number; dateTimeZone: string; width?: number; height?: number; previewUrl?: string; _projectionType?: string; isProcessed?: boolean; _thumbSize?: number; }[]; totalEntries: number; }; } ``` ### `VideoCaptureOptions` [Section titled “VideoCaptureOptions”](#videocaptureoptions) ```typescript export interface VideoCaptureOptions { // Define any specific options needed for capturing a video resolution?: '4K' | '2K'; frameRate?: number; bitrate?: number; } ``` ### `LivePreviewOptions` [Section titled “LivePreviewOptions”](#livepreviewoptions) ```typescript export interface LivePreviewOptions { displayInFront?: boolean; cropPreview?: boolean; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-rudderstack > Capacitor API that mirrors the public surface of `rudder-sdk-cordova`. ## Overview [Section titled “Overview”](#overview) Capacitor API that mirrors the public surface of `rudder-sdk-cordova`. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `initialize` - Initializes the RudderStack client. * `identify` - Sends an identify call for the provided user id. * `group` - Sends a group call for the provided group id. * `track` - Sends a track call for the provided event name. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------ | ------------------------------------------------------------------------ | | `initialize` | Initializes the RudderStack client. | | `identify` | Sends an identify call for the provided user id. | | `group` | Sends a group call for the provided group id. | | `track` | Sends a track call for the provided event name. | | `screen` | Sends a screen call for the provided screen name. | | `alias` | Aliases the current user to a new identifier. | | `reset` | Resets the current RudderStack identity state. | | `flush` | Flushes queued events immediately. | | `putDeviceToken` | Sets the push token that RudderStack forwards to supported destinations. | | `setAdvertisingId` | See the source definitions for current behavior. | | `putAdvertisingId` | Sets a custom advertising id value. | | `setAnonymousId` | See the source definitions for current behavior. | | `putAnonymousId` | Sets a custom anonymous id value. | | `optOut` | Toggles RudderStack tracking opt-out. | | `getPluginVersion` | Returns the plugin version marker from the native implementation. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-rudderstack](https://github.com/Cap-go/capacitor-rudderstack/). # Getting Started > Install @capgo/capacitor-rudderstack and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-rudderstack bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { nativePlugin } from '@capgo/capacitor-rudderstack'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `initialize` [Section titled “initialize”](#initialize) Initializes the RudderStack client. The method keeps the Cordova signature, so the second argument may be either a config object or a Rudder options object. ```typescript import { nativePlugin } from '@capgo/capacitor-rudderstack'; await nativePlugin.initialize('value'); ``` ### `identify` [Section titled “identify”](#identify) Sends an identify call for the provided user id. ```typescript import { nativePlugin } from '@capgo/capacitor-rudderstack'; await nativePlugin.identify('value'); ``` ### `group` [Section titled “group”](#group) Sends a group call for the provided group id. ```typescript import { nativePlugin } from '@capgo/capacitor-rudderstack'; await nativePlugin.group('value'); ``` ### `track` [Section titled “track”](#track) Sends a track call for the provided event name. ```typescript import { nativePlugin } from '@capgo/capacitor-rudderstack'; await nativePlugin.track('value'); ``` ### `screen` [Section titled “screen”](#screen) Sends a screen call for the provided screen name. ```typescript import { nativePlugin } from '@capgo/capacitor-rudderstack'; await nativePlugin.screen('value'); ``` ### `alias` [Section titled “alias”](#alias) Aliases the current user to a new identifier. ```typescript import { nativePlugin } from '@capgo/capacitor-rudderstack'; await nativePlugin.alias('value'); ``` ### `reset` [Section titled “reset”](#reset) Resets the current RudderStack identity state. ```typescript import { nativePlugin } from '@capgo/capacitor-rudderstack'; await nativePlugin.reset(); ``` ### `flush` [Section titled “flush”](#flush) Flushes queued events immediately. ```typescript import { nativePlugin } from '@capgo/capacitor-rudderstack'; await nativePlugin.flush(); ``` ### `putDeviceToken` [Section titled “putDeviceToken”](#putdevicetoken) Sets the push token that RudderStack forwards to supported destinations. ```typescript import { nativePlugin } from '@capgo/capacitor-rudderstack'; await nativePlugin.putDeviceToken('value'); ``` ### `setAdvertisingId` [Section titled “setAdvertisingId”](#setadvertisingid) See the source definitions for the current contract. ```typescript import { nativePlugin } from '@capgo/capacitor-rudderstack'; await nativePlugin.setAdvertisingId('value'); ``` ### `putAdvertisingId` [Section titled “putAdvertisingId”](#putadvertisingid) Sets a custom advertising id value. ```typescript import { nativePlugin } from '@capgo/capacitor-rudderstack'; await nativePlugin.putAdvertisingId('value'); ``` ### `setAnonymousId` [Section titled “setAnonymousId”](#setanonymousid) See the source definitions for the current contract. ```typescript import { nativePlugin } from '@capgo/capacitor-rudderstack'; await nativePlugin.setAnonymousId('value'); ``` ### `putAnonymousId` [Section titled “putAnonymousId”](#putanonymousid) Sets a custom anonymous id value. ```typescript import { nativePlugin } from '@capgo/capacitor-rudderstack'; await nativePlugin.putAnonymousId('value'); ``` ### `optOut` [Section titled “optOut”](#optout) Toggles RudderStack tracking opt-out. ```typescript import { nativePlugin } from '@capgo/capacitor-rudderstack'; await nativePlugin.optOut(true); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `RudderConfiguration` [Section titled “RudderConfiguration”](#rudderconfiguration) Supported configuration keys for the underlying RudderStack native SDKs. ```typescript export interface RudderConfiguration { /** * RudderStack data plane URL. */ dataPlaneUrl?: string; /** * Number of events to batch before a flush. */ flushQueueSize?: number; /** * Database row threshold that triggers pruning on Android and iOS. */ dbCountThreshold?: number; /** * Server config refresh interval in hours. */ configRefreshInterval?: number; /** * RudderStack log verbosity. */ logLevel?: RudderLogLevelValue; /** * Sleep timeout / sleep count used by the native SDK. */ sleepTimeOut?: number; /** * Android only. Lets the native SDK collect the advertising identifier automatically. */ autoCollectAdvertId?: boolean; /** * Tracks `Application Installed`, `Application Updated`, and `Application Opened` automatically. */ trackLifecycleEvents?: boolean; /** * RudderStack control plane URL. */ controlPlaneUrl?: string; /** * Enables automatic screen tracking where supported by the native SDK. */ recordScreenViews?: boolean; /** * Ignored in this Capacitor port. * * The Cordova SDK uses this field to bootstrap native destination factories from companion plugins. * Those extension packages are not implemented in this first Capacitor release. */ factories?: any[]; } ``` ### `RudderOptions` [Section titled “RudderOptions”](#rudderoptions) RudderStack per-call options. ```typescript export interface RudderOptions { /** * External identifiers forwarded with the event. */ externalIds?: Record<string, string>; /** * Destination enablement flags keyed by integration name. */ integrations?: Record<string, boolean>; } ``` ### `RudderTraits` [Section titled “RudderTraits”](#ruddertraits) Traits payload accepted by `identify` and `group`. ```typescript export type RudderTraits = Record<string, any>; ``` ### `RudderProperties` [Section titled “RudderProperties”](#rudderproperties) Properties payload accepted by `track` and `screen`. ```typescript export type RudderProperties = Record<string, any>; ``` ### `PluginVersionResult` [Section titled “PluginVersionResult”](#pluginversionresult) Plugin version payload. ```typescript export interface PluginVersionResult { /** * Version identifier returned by the platform implementation. */ version: string; } ``` ### `RudderLogLevelValue` [Section titled “RudderLogLevelValue”](#rudderloglevelvalue) RudderStack log level values exposed for migration convenience. ```typescript export type RudderLogLevelValue = 0 | 1 | 2 | 3 | 4 | 5; ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-screen-orientation > Capacitor Screen Orientation Plugin interface. ## Overview [Section titled “Overview”](#overview) Capacitor Screen Orientation Plugin interface. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `orientation` - Get the current screen orientation. * `lock` - Lock the screen orientation to a specific type. * `unlock` - Unlock the screen orientation. * `startOrientationTracking` - Start tracking device orientation using motion sensors. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | -------------------------- | ------------------------------------------------------- | | `orientation` | Get the current screen orientation. | | `lock` | Lock the screen orientation to a specific type. | | `unlock` | Unlock the screen orientation. | | `startOrientationTracking` | Start tracking device orientation using motion sensors. | | `stopOrientationTracking` | Stop tracking device orientation using motion sensors. | | `isOrientationLocked` | Check if device orientation lock is currently enabled. | | `addListener` | Listen for screen orientation changes. | | `removeAllListeners` | Remove all listeners for this plugin. | | `getPluginVersion` | Get the native plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-screen-orientation](https://github.com/Cap-go/capacitor-screen-orientation/). # Getting Started > Install @capgo/capacitor-screen-orientation and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-screen-orientation bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { ScreenOrientation } from '@capgo/capacitor-screen-orientation'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `orientation` [Section titled “orientation”](#orientation) Get the current screen orientation. Returns the current orientation of the device screen. ```typescript import { ScreenOrientation } from '@capgo/capacitor-screen-orientation'; const result = await ScreenOrientation.orientation(); console.log('Current orientation:', result.type); ``` ### `lock` [Section titled “lock”](#lock) Lock the screen orientation to a specific type. Locks the screen to the specified orientation. On iOS, if bypassOrientationLock is true, it will also start tracking physical device orientation using motion sensors. Note: The UI will still respect the user’s orientation lock setting. Motion tracking allows you to detect how the device is physically held even when the UI doesn’t rotate. ```typescript import { ScreenOrientation } from '@capgo/capacitor-screen-orientation'; // Standard lock await ScreenOrientation.lock({ orientation: 'landscape' }); // Lock with motion tracking on iOS await ScreenOrientation.lock({ orientation: 'portrait', bypassOrientationLock: true }); ``` ### `unlock` [Section titled “unlock”](#unlock) Unlock the screen orientation. Allows the screen to rotate freely based on device position. Also stops any motion-based orientation tracking if it was enabled. ```typescript import { ScreenOrientation } from '@capgo/capacitor-screen-orientation'; await ScreenOrientation.unlock(); ``` ### `startOrientationTracking` [Section titled “startOrientationTracking”](#startorientationtracking) Start tracking device orientation using motion sensors. This method is useful when you want to track the device’s physical orientation independently from the screen orientation lock. It uses Core Motion on iOS to detect orientation changes. ```typescript import { ScreenOrientation } from '@capgo/capacitor-screen-orientation'; await ScreenOrientation.startOrientationTracking({ bypassOrientationLock: true }); // Listen for changes ScreenOrientation.addListener('screenOrientationChange', (result) => { console.log('Orientation changed:', result.type); }); ``` ### `stopOrientationTracking` [Section titled “stopOrientationTracking”](#stoporientationtracking) Stop tracking device orientation using motion sensors. Stops the motion-based orientation tracking if it was started. ```typescript import { ScreenOrientation } from '@capgo/capacitor-screen-orientation'; await ScreenOrientation.stopOrientationTracking(); ``` ### `isOrientationLocked` [Section titled “isOrientationLocked”](#isorientationlocked) Check if device orientation lock is currently enabled. This method compares the physical device orientation (from motion sensors) with the UI orientation. If they differ, orientation lock is enabled. Note: This requires motion tracking to be active via startOrientationTracking() or lock() with bypassOrientationLock: true. Works on both iOS (Core Motion) and Android (Accelerometer). ```typescript import { ScreenOrientation } from '@capgo/capacitor-screen-orientation'; // Start motion tracking first await ScreenOrientation.startOrientationTracking({ bypassOrientationLock: true }); // Check lock status const status = await ScreenOrientation.isOrientationLocked(); if (status.locked) { console.log('Orientation lock is ON'); console.log('Physical:', status.physicalOrientation); console.log('UI:', status.uiOrientation); } ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `ScreenOrientationResult` [Section titled “ScreenOrientationResult”](#screenorientationresult) Result returned by the orientation() method. ```typescript export interface ScreenOrientationResult { /** * The current orientation type. * * @since 1.0.0 */ type: OrientationType; } ``` ### `OrientationLockOptions` [Section titled “OrientationLockOptions”](#orientationlockoptions) Options for locking the screen orientation. ```typescript export interface OrientationLockOptions { /** * The orientation type to lock to. * * @since 1.0.0 */ orientation: OrientationLockType; /** * Whether to track physical device orientation using motion sensors. * When true, uses device motion sensors to detect the true physical * orientation of the device, even when the device orientation lock is enabled. * * **Important:** This does NOT bypass the UI orientation lock. * The screen will still respect the user's orientation lock setting. * This option only affects orientation detection/tracking - you'll receive * orientation change events based on how the device is physically held, * but the UI will not rotate if orientation lock is enabled. * * Supported on iOS (Core Motion) and Android (Accelerometer). * * @default false * @since 1.0.0 */ bypassOrientationLock?: boolean; } ``` ### `StartOrientationTrackingOptions` [Section titled “StartOrientationTrackingOptions”](#startorientationtrackingoptions) Options for starting orientation tracking using motion sensors. ```typescript export interface StartOrientationTrackingOptions { /** * Whether to track physical device orientation using motion sensors. * When true, uses device motion sensors to detect the true physical * orientation of the device, even when the device orientation lock is enabled. * * **Important:** This does NOT bypass the UI orientation lock. * This only enables detection of the physical orientation. * * Supported on iOS (Core Motion) and Android (Accelerometer). * * @default false * @since 1.0.0 */ bypassOrientationLock?: boolean; } ``` ### `OrientationLockStatusResult` [Section titled “OrientationLockStatusResult”](#orientationlockstatusresult) Result returned by the isOrientationLocked() method. ```typescript export interface OrientationLockStatusResult { /** * Whether the device orientation lock is currently enabled. * * This is determined by comparing the physical device orientation * (from motion sensors) with the UI orientation. If they differ, * orientation lock is enabled. * * Available on iOS (Core Motion) and Android (Accelerometer) when motion tracking is active. * * @since 1.0.0 */ locked: boolean; /** * The physical orientation of the device from motion sensors. * Available when motion tracking is active (iOS and Android). * * @since 1.0.0 */ physicalOrientation?: OrientationType; /** * The current UI orientation reported by the system. * * @since 1.0.0 */ uiOrientation: OrientationType; } ``` ### `OrientationType` [Section titled “OrientationType”](#orientationtype) Orientation type that describes the orientation state of the device. ```typescript export type OrientationType = 'portrait-primary' | 'portrait-secondary' | 'landscape-primary' | 'landscape-secondary'; ``` ### `OrientationLockType` [Section titled “OrientationLockType”](#orientationlocktype) Orientation lock type that can be used to lock the device orientation. ```typescript export type OrientationLockType = | 'any' | 'natural' | 'landscape' | 'portrait' | 'portrait-primary' | 'portrait-secondary' | 'landscape-primary' | 'landscape-secondary'; ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-screen-recorder > Capacitor Screen Recorder Plugin for recording the device screen. Allows you to capture video recordings of the screen with optional audio. ## Overview [Section titled “Overview”](#overview) Capacitor Screen Recorder Plugin for recording the device screen. Allows you to capture video recordings of the screen with optional audio. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `start` - Start recording the device screen. * `stop` - Stop the current screen recording. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------ | ---------------------------------------- | | `start` | Start recording the device screen. | | `stop` | Stop the current screen recording. | | `getPluginVersion` | Get the native Capacitor plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-screen-recorder](https://github.com/Cap-go/capacitor-screen-recorder/). # Getting Started > Install @capgo/capacitor-screen-recorder and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-screen-recorder bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { ScreenRecorder } from '@capgo/capacitor-screen-recorder'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `start` [Section titled “start”](#start) Start recording the device screen. Initiates screen recording with optional audio capture. The user will be prompted to grant screen recording permissions if not already granted. On iOS, the system recording UI will be displayed. On Android, the recording starts immediately after permission is granted. ```typescript import { ScreenRecorder } from '@capgo/capacitor-screen-recorder'; // Start recording without audio await ScreenRecorder.start(); // Start recording with audio await ScreenRecorder.start({ recordAudio: true }); ``` ### `stop` [Section titled “stop”](#stop) Stop the current screen recording. Stops the active screen recording and saves the video to the device’s camera roll or gallery. On iOS, the system will show a preview of the recording. On Android, the video is saved directly to the gallery. ```typescript import { ScreenRecorder } from '@capgo/capacitor-screen-recorder'; await ScreenRecorder.stop(); console.log('Recording saved to gallery'); ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-shake > Capacitor Shake Plugin interface for detecting shake gestures on mobile devices. This plugin allows you to listen for shake events and get plugin version information. ## Overview [Section titled “Overview”](#overview) Capacitor Shake Plugin interface for detecting shake gestures on mobile devices. This plugin allows you to listen for shake events and get plugin version information. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `addListener` - Listen for shake event on the device. * `getPluginVersion` - Get the native Capacitor plugin version. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------ | ---------------------------------------- | | `addListener` | Listen for shake event on the device. | | `getPluginVersion` | Get the native Capacitor plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-shake](https://github.com/Cap-go/capacitor-shake/). # Getting Started > Install @capgo/capacitor-shake and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-shake bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { CapacitorShake } from '@capgo/capacitor-shake'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `addListener` [Section titled “addListener”](#addlistener) Listen for shake event on the device. Registers a listener that will be called whenever a shake gesture is detected. The shake detection uses the device’s accelerometer to identify shake patterns. ```typescript import { CapacitorShake } from '@capgo/capacitor-shake'; const listener = await CapacitorShake.addListener('shake', () => { console.log('Shake detected!'); }); // To remove the listener: await listener.remove(); ``` ### `getPluginVersion` [Section titled “getPluginVersion”](#getpluginversion) Get the native Capacitor plugin version. Returns the current version of the native plugin implementation. ```typescript import { CapacitorShake } from '@capgo/capacitor-shake'; const { version } = await CapacitorShake.getPluginVersion(); console.log('Plugin version:', version); ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-share-target > Capacitor Share Target Plugin interface. ## Overview [Section titled “Overview”](#overview) Capacitor Share Target Plugin interface. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `addListener` - Listen for shareReceived event. * `removeAllListeners` - Remove all listeners for this plugin. * `getPluginVersion` - Get the native Capacitor plugin version. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | -------------------- | ---------------------------------------- | | `addListener` | Listen for shareReceived event. | | `removeAllListeners` | Remove all listeners for this plugin. | | `getPluginVersion` | Get the native Capacitor plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-share-target](https://github.com/Cap-go/capacitor-share-target/). # Getting Started > Install @capgo/capacitor-share-target and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-share-target bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { CapacitorShareTarget } from '@capgo/capacitor-share-target'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `addListener` [Section titled “addListener”](#addlistener) Listen for shareReceived event. Registers a listener that will be called when content is shared to the application from another app. The callback receives event data containing title, texts, and files. ```typescript import { CapacitorShareTarget } from '@capgo/capacitor-share-target'; const listener = await CapacitorShareTarget.addListener('shareReceived', (event) => { console.log('Title:', event.title); console.log('Texts:', event.texts); event.files?.forEach(file => { console.log(`File: ${file.name} (${file.mimeType})`); }); }); // To remove the listener: await listener.remove(); ``` ### `removeAllListeners` [Section titled “removeAllListeners”](#removealllisteners) Remove all listeners for this plugin. ```typescript import { CapacitorShareTarget } from '@capgo/capacitor-share-target'; await CapacitorShareTarget.removeAllListeners(); ``` ### `getPluginVersion` [Section titled “getPluginVersion”](#getpluginversion) Get the native Capacitor plugin version. Returns the current version of the native plugin implementation. ```typescript import { CapacitorShareTarget } from '@capgo/capacitor-share-target'; const { version} = await CapacitorShareTarget.getPluginVersion(); console.log('Plugin version:', version); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `ShareReceivedEvent` [Section titled “ShareReceivedEvent”](#sharereceivedevent) Event data received when content is shared to the application. ```typescript export interface ShareReceivedEvent { /** * The title of the shared content. * * @since 0.1.0 */ title: string; /** * Array of text content shared to the application. * * @since 0.1.0 */ texts: string[]; /** * Array of files shared to the application. * * @since 0.2.0 */ files: SharedFile[]; } ``` ### `SharedFile` [Section titled “SharedFile”](#sharedfile) Represents a file shared to the application. ```typescript export interface SharedFile { /** * The URI of the shared file. On Android/iOS this will be a file path or data URL. * On web this will be a cached URL accessible via fetch. * * @since 0.1.0 */ uri: string; /** * The name of the shared file, with or without extension. * * @since 0.1.0 */ name: string; /** * The MIME type of the shared file. * * @since 0.1.0 */ mimeType: string; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-sim > Capacitor SIM Plugin for retrieving information from device SIM cards. ## Overview [Section titled “Overview”](#overview) Capacitor SIM Plugin for retrieving information from device SIM cards. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `getSimCards` - Get information from the device’s SIM cards. * `checkPermissions` - Check permission to access SIM card information. * `requestPermissions` - Request permission to access SIM card information. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | -------------------- | -------------------------------------------------- | | `getSimCards` | Get information from the device’s SIM cards. | | `checkPermissions` | Check permission to access SIM card information. | | `requestPermissions` | Request permission to access SIM card information. | | `getPluginVersion` | Get the native Capacitor plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-sim](https://github.com/Cap-go/capacitor-sim/). # Getting Started > Install @capgo/capacitor-sim and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-sim bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { Sim } from '@capgo/capacitor-sim'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `getSimCards` [Section titled “getSimCards”](#getsimcards) Get information from the device’s SIM cards. Retrieves details about all SIM cards installed in the device. On dual-SIM devices, returns information for both SIM cards. Requires READ\_PHONE\_STATE permission on Android. ```typescript import { Sim } from '@capgo/capacitor-sim'; const { simCards } = await SimPlugin.getSimCards(); simCards.forEach((sim, index) => { console.log(`SIM ${index + 1}:`); console.log(` Carrier: ${sim.carrierName}`); console.log(` Country: ${sim.isoCountryCode}`); console.log(` MCC: ${sim.mobileCountryCode}`); console.log(` MNC: ${sim.mobileNetworkCode}`); }); ``` ### `checkPermissions` [Section titled “checkPermissions”](#checkpermissions) Check permission to access SIM card information. Checks if the app has permission to read SIM card data. On Android, checks READ\_PHONE\_STATE permission. On iOS, the status is always granted. On Web, the status is always denied. ```typescript import { Sim } from '@capgo/capacitor-sim'; const status = await SimPlugin.checkPermissions(); if (status.readSimCard === 'granted') { console.log('Permission granted'); } else { console.log('Permission not granted'); } ``` ### `requestPermissions` [Section titled “requestPermissions”](#requestpermissions) Request permission to access SIM card information. Prompts the user to grant permission to read SIM card data. On Android, requests READ\_PHONE\_STATE permission. On iOS, the status is always granted without prompting. On Web, the status remains denied. ```typescript import { Sim } from '@capgo/capacitor-sim'; const status = await SimPlugin.requestPermissions(); if (status.readSimCard === 'granted') { // Now you can call getSimCards() const simCards = await SimPlugin.getSimCards(); } ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `GetSimCardsResult` [Section titled “GetSimCardsResult”](#getsimcardsresult) Result returned by . ```typescript export interface GetSimCardsResult { simCards: SimCard[]; } ``` ### `PermissionStatus` [Section titled “PermissionStatus”](#permissionstatus) Result of a permission check or request. ```typescript export interface PermissionStatus { readSimCard: PermissionState; } ``` ### `SimCard` [Section titled “SimCard”](#simcard) A SIM card description. ```typescript export interface SimCard { /** * Android only: Phone number for this SIM slot, when available. * * @since 1.0.0 */ number?: string; /** * Android only: Unique subscription identifier. * * @since 1.1.0 */ subscriptionId?: string; /** * Android only: Physical SIM slot index for this subscription. * * @since 1.1.0 */ simSlotIndex?: number; /** * iOS only: Indicates whether the carrier supports VoIP. * * @since 1.0.0 */ allowsVOIP?: boolean; /** * Display name of the cellular service provider. * * On iOS 16.4+ the system may return placeholder values such as `--`. * See https://github.com/jonz94/capacitor-sim/issues/8 for details. * * @since 1.0.0 */ carrierName: string; /** * ISO 3166-1 alpha-2 country code of the service provider. * * On iOS 16.4+ the system may return an empty string or `--`. * See https://github.com/jonz94/capacitor-sim/issues/8 for details. * * @since 1.0.0 */ isoCountryCode: string; /** * Mobile Country Code (MCC) of the service provider. * * On iOS 16.4+ the system may return placeholder values such as `65535`. * See https://github.com/jonz94/capacitor-sim/issues/8 for details. * * @since 1.0.0 */ mobileCountryCode: string; /** * Mobile Network Code (MNC) of the service provider. * * On iOS 16.4+ the system may return placeholder values such as `65535`. * See https://github.com/jonz94/capacitor-sim/issues/8 for details. * * @since 1.0.0 */ mobileNetworkCode: string; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-social-login > All social logins in one plugin. ## Overview [Section titled “Overview”](#overview) All social logins in one plugin. ## Video Walkthrough [Section titled “Video Walkthrough”](#video-walkthrough) Watch a quick demo of the plugin setup and login flow in action. [Capgo Social Login plugin overview](https://www.youtube-nocookie.com/embed/iTINYxvSJrE) ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `initialize` - Initialize the plugin. * `login` - Login with the selected provider. * `logout` - Logout. * `isLoggedIn` - IsLoggedIn. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `initialize` | Initialize the plugin. | | `login` | Login with the selected provider. | | `logout` | Logout. | | `isLoggedIn` | IsLoggedIn. | | `getAuthorizationCode` | Get the current authorization code. | | `refresh` | Refresh the access token. | | `refreshToken` | OAuth2 refresh-token helper (feature parity with Capawesome OAuth). | | `handleRedirectCallback` | Web-only: handle the OAuth redirect callback and return the parsed result. | | `decodeIdToken` | Decode a JWT (typically an OIDC ID token) into its claims. | | `getAccessTokenExpirationDate` | Convert an access token expiration timestamp (milliseconds since epoch) to an ISO date string. | | `isAccessTokenAvailable` | Check if an access token is available (non-empty). | | `isAccessTokenExpired` | Check if an access token is expired. | | `isRefreshTokenAvailable` | Check if a refresh token is available (non-empty). | | `providerSpecificCall` | Execute provider-specific calls. | | `getPluginVersion` | Get the native Capacitor plugin version. | | `openSecureWindow` | Opens a secured window for OAuth2 authentication. For web, you should have the code in the redirected page to use a broadcast channel to send the redirected url to the app Something like: `html <html> <head></head> <body> <script> const searchParams = new URLSearchParams(location.search) if (searchParams.has("code")) { new BroadcastChannel("my-channel-name").postMessage(location.href); window.close(); } </script> </body> </html> `For mobile, you should have a redirect uri that opens the app, something like: `myapp://oauth_callback/` And make sure to register it in the app’s info.plist: `xml <key>CFBundleURLTypes</key> <array> <dict> <key>CFBundleURLSchemes</key> <array> <string>myapp</string> </array> </dict> </array> `And in the AndroidManifest.xml file: `xml <activity> <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:host="oauth_callback" android:scheme="myapp" /> </intent-filter> </activity> `. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-social-login](https://github.com/Cap-go/capacitor-social-login/). # Apple login on Android > This guide provides a comprehensive walkthrough on setting up Apple Login using Capacitor for iOS devices, detailing each step to ensure a smooth integration process. Apple login on android is hacky. Apple has no official support for `Sign in with Apple` on Android, so the solution is slightly hacky. Android currently uses a chrome tabs to display an OAuth2 website. This approach has the challenges: * Difficult configuration * A backend is required ## Understanding the flow on android. [Section titled “Understanding the flow on android.”](#understanding-the-flow-on-android) Let me use a diagram to explain the flow on android: ``` flowchart TD A("await SocialLogin.login()") -->|Handled in the plugin|B(Generate the login URL) B --> |Pass the link| C(Open the Chrome browser) C --> D(Wait for the user to login) D --> |Apple redirects to your backend|E(Handle the data returned from Apple) E --> F(Redirect back to the app) F --> G(Return to JS) ``` Now that you are aware of the challlanges and the flow, let’s begin the configuration. ## Creating the service ID [Section titled “Creating the service ID”](#creating-the-service-id) 1. Login into the [Apple Developer Portal](https://developer.apple.com). 2. Click on `Identifiers`. ![Apple Developer Portal Identifiers section](/social-login-assets/apple_dev_portal_iden.png) You should see a screen that looks like this: ![Apple Developer Portal Identifiers screen](/social-login-assets/apple_dev_portal_iden_2.png) 1. Ensure that this field says `App IDs` 2. Make sure that you can find your App ID. Note If you don’t have configured Apple Login for IOS, you will have to create one. For me, I already have one created. The app ID I will use is `me.wcaleniewolny.test.ionic.vue`. If you don’t have one, please create one using the [create app step](#creating-the-app). 3. Make sure that the `Sign in with Apple` capability is enabled for your app 1. Click on your app ![Selecting your app from the list](/social-login-assets/apple_dev_click_on_app.png) 2. Ensure that the `Sign in with Apple` capability is enabled ![Sign in with Apple capability enabled checkbox](/social-login-assets/apple_dev_sign_in_with_apple_enabled.png) 3. If it isn’t enabled, enable it. 4. Go back to all `All Identifiers` ![All Identifiers navigation button](/social-login-assets/apple_dev_go_back_iden.png) 5. Click on `App Ids` and go to `Services IDs` ![Navigation to Services IDs section](/social-login-assets/apple_dev_go_to_services_id.png) 6. Creare a new identifier 1. Click on the plus button ![Add new service ID button](/social-login-assets/apple_dev_iden_add.png) 2. Select `Servcice IDs` and click `Continue` ![Selecting Service IDs option](/social-login-assets/apple_dev_service_and_cont.png) 3. Enter a description and a identifiers and click `Continuie`. ![Entering service ID details](/social-login-assets/apple_dev_reg_service_2.png) Note This `identifiers` will become the `clientId` that you will pass in the `initialize` function AND `ANDROID_SERVICE_ID` for the backend. **Please save it!!!** Note Service ID doesn’t have to match the App ID, but I recommend setting the service ID to `YOUR_APP_ID.service` . As a reminder, I am using `me.wcaleniewolny.test.ionic.vue` for my app ID but I am using `ee.forgr.io.ionic.service2` as the service ID. 4. Please verify the details and click `Register` ![Confirming service ID registration](/social-login-assets/apple_dev_service_ref_fin.png) 5. Click on the the newly created service ![Selecting newly created service ID](/social-login-assets/apple_dev_open_serv.png) 6. Enable the `Sign in with Apple` option ![Enabling Sign in with Apple for service ID](/social-login-assets/apple_dev_serv_enable_sign_with_apple.png) 7. Configure the `Sign In with Apple` ![Configure button for Sign in with Apple](/social-login-assets/apple_dev_conf_serv_sign_with_apple.png) 8. Ensure that the `Primary App ID` is set to the App ID configured in the previous step ![Setting Primary App ID dropdown](/social-login-assets/apple_dev_service_prim_id.png) 9. Add the domain that you are going to host you backend on. ![Setting domain and return URL fields](/social-login-assets/apple_dev_serv_create_next.png) Note This backend **has** to be running on HTTPS. As for the `Return URLs`, you might want to come back to this after reading the next section of this tutorial and after configuring the backend. For the purposes of this tutorial, I will use `https://xyz.wcaleniewolny.me/login/callback` for the return URL and `xyz.wcaleniewolny.me` the domain. Press next. 10. Confirm the data and click `Done` ![Confirming domain and return URL configuration](/social-login-assets/apple_dev_serv_conf_done.png) 11. Click on `Continue` ![Continue button for service configuration](/social-login-assets/apple_dev_cont_serv_creat.png) 12. Click on `Save` ![Save button for service configuration](/social-login-assets/apple_dev_cont_serv_creat_save.png) ## Creating the key [Section titled “Creating the key”](#creating-the-key) 1. Go back to all `All Identifiers` ![All Identifiers navigation button](/social-login-assets/apple_dev_go_back_iden.png) 2. Click on `Keys` ![Keys section in Apple Developer Portal](/social-login-assets/apple_dev_key_selc.png) 3. Click on the plus icon ![Add new key button](/social-login-assets/apple_dev_key_plus.png) 4. Name your key ![Entering key name field](/social-login-assets/apple_key_name.png) Note This name isn’t important, you can put anything. 5. Select `Sign in with Apple` and click `Configure` ![Enabling and configuring Sign in with Apple for the key](/social-login-assets/apple_dev_key_sing_apple_conf.png) 6. Select the primary App ID, and press `Save` ![Selecting primary App ID for the key](/social-login-assets/apple_dev_key_prim_app_id.png) Note This must be the same App ID as the ID in the previous steps. 7. Click on `Continue` ![Continue button for key configuration](/social-login-assets/apple_dev_key_const.png) 8. Click on `Register` ![Register button for key creation](/social-login-assets/apple_dev_key_reg.png) 9. Copy the key ID and download the key. ![Key ID and download button screen](/social-login-assets/apple_dev_key_downl.png) Caution **IMPORTANT:** Save this ID, in the backend it will be called `KEY_ID`. Download the key. Make sure to never share this key. 10. Find the downloaded key and save it in the backend folder. ![Downloaded key file](/social-login-assets/apple_dev_downloaded_key.png) ## Getting the Team ID [Section titled “Getting the Team ID”](#getting-the-team-id) In order to use `Login with Apple` on Android, you need to get the `Team ID`. It will be used in the backend. 1. Go to [this website](https://developer.apple.com/account/) and scroll down 2. Find the `Team ID` ![Team ID location in developer account](/social-login-assets/apple_dev_team_id.png) ## Configuring the app redirect [Section titled “Configuring the app redirect”](#configuring-the-app-redirect) As you saw in the diagram, the backend performs a step called `Redirect back to the app`. This requires manual changes to your app. 1. Modify the `AndroidManifest.xml` 1. Open the file, I will use `AndroidStudio` ![AndroidManifest.xml file in Android Studio](/social-login-assets/studio_android_manifest_file.png) 2. Find the `MainActivity` and add the following Intent filter ![Intent filter code to add in MainActivity](/social-login-assets/studio_manifest_code_to_add.png) ```xml <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="capgo-demo-app" android:host="path" /> </intent-filter> ``` 2. Modify the `MainActivity` 1. Please open the `MainActivity` ![MainActivity.java file in Android Studio](/social-login-assets/studio_main_activ_file.png) 2. Add the following code: ![Code to add to MainActivity for handling deep links](/social-login-assets/studio_main_actv_new_code.png) ```java @Override protected void onNewIntent(Intent intent) { String action = intent.getAction(); Uri data = intent.getData(); if (Intent.ACTION_VIEW.equals(action) && data != null) { PluginHandle pluginHandle = getBridge().getPlugin("SocialLogin"); if (pluginHandle == null) { Log.i("Apple Login Intent", "SocialLogin login handle is null"); return; } Plugin plugin = pluginHandle.getInstance(); if (!(plugin instanceof SocialLoginPlugin)) { Log.i("Apple Login Intent", "SocialLogin plugin instance is not SocialLoginPlugin"); return; } ((SocialLoginPlugin) plugin).handleAppleLoginIntent(intent); return; } super.onNewIntent(intent); } ``` Caution This example assumes that you don’t have any deep links configured. If you do, please adjust the code Note You have just added a new deep link into your app. The deep link will look something like this: `capgo-demo-app://path`. You can change the `android:scheme` and the `android:host` to modify how this deep link looks. **Important:** In the backend configuration, this deep link will become `BASE_REDIRECT_URL` ## Backend configuration [Section titled “Backend configuration”](#backend-configuration) A backend is required for Android, but configuring a backend will also impact IOS. An example backend is provided [here](https://github.com/WcaleNieWolny/capgo-social-login-backend-demo/blob/main/index.ts) This example provides the following: * A simple JSON database * A way to request the JWT from Apple’s servers * A simple JWT verification Note I use `PM2` in order to host this example. An example `ecosystem.config.js` can be found [here](https://github.com/WcaleNieWolny/capgo-social-login-backend-demo/blob/main/ecosystem.config.js.example) Given everything that I said in this tutorial, here is how the `env` section would look: * `ANDROID_SERVICE_ID` = Service ID * `IOS_SERVICE_ID` = App ID ```js env: { PRIVATE_KEY_FILE: "AuthKey_U93M8LBQK3.p8", KEY_ID: "U93M8LBQK3", TEAM_ID: "UVTJ336J2D", ANDROID_SERVICE_ID: "ee.forgr.io.ionic.starter.service2", IOS_SERVICE_ID: "me.wcaleniewolny.test.ionic.vue", PORT: 3000, REDIRECT_URI: "https://xyz.wcaleniewolny.me/login/callback", BASE_REDIRECT_URL: "capgo-demo-app://path" } ``` #### Using the plugin [Section titled “Using the plugin”](#using-the-plugin) The usage of the `login` function doesn’t change, it’s the same as IOS. Please take a look at that section for more info. **HOWEVER**, the `initialize` method changes a bit. ```typescript await SocialLogin.initialize({ apple: { clientId: 'ee.forgr.io.ionic.starter.service2', redirectUrl: 'https://appleloginvps.wcaleniewolny.me/login/callback' } }) ``` Danger Note, that adding `redirectUrl` **WILL** affect IOS !!!!! ## Creating the app [Section titled “Creating the app”](#creating-the-app) Note If you already have an App ID, you can skip this step. Don’t follow this step if you have configured Apple Login for IOS. 1. If you don’t already have an App ID, click on the plus button ![Add new identifier plus button](/social-login-assets/apple_dev_iden_plus.png) 2. Select `App IDs` and click continue ![Selecting App IDs type](/social-login-assets/apple_dev_new_app_id.png) 3. Click on type `App` and click `Continue` ![Selecting App type](/social-login-assets/apple_dev_new_app_type.png) 4. Enter the description and the app ID ![Entering app description and bundle ID](/social-login-assets/apple_dev_new_app_desc_id.png) 5. Enable `Sign with Apple` capability ![Enabling Sign in with Apple capability](/social-login-assets/apple_dev_enable_sign_with_apple.png) 6. Click `Continue` ![Continue button for app registration](/social-login-assets/apple_dev_register_continue.png) 7. Confirm the details and click `Register` ![Confirming app registration details](/social-login-assets/apple_dev_confirm_register.png) # Apple Login Setup > This guide provides detailed instructions on setting up Apple Login using Capacitor, covering all necessary steps and requirements for a successful integration. ### Introduction [Section titled “Introduction”](#introduction) In this guide, you are going to learn how to configure Apple Login with Capacitor. In order to do this, you will need the following: * an Apple Developer Account * A computer running macOS (IOS only) * Xcode installed (IOS only) * A custom backend (Android only) # Apple login on IOS > This comprehensive guide will walk you through the process of setting up Apple Login using Capacitor on iOS devices, ensuring a seamless integration by covering all necessary steps and configurations. Let’s break down what you are going to need in order to setup Apple login on IOS. 1. Configure the capabilities of your app. In order to do this, please open Xcode, click on `App` ![App XCode](/social-login-assets/app-xcode.png) 2. Make sure that you select the right target. ![XCode App Target](/social-login-assets/xcode-app-target.png) 3. Please make sure that you add the `Sign in with Apple` capability. ![App XCode Add Capability](/social-login-assets/app-xcode-add-cap.png) ![App XCode Add Capability](/social-login-assets/sign-with-apple-cap.png) Caution If you don’t see the `Sign in with Apple` capability, configure the [Account & Organizational Data Sharing](https://developer.apple.com/account/resources/services/cwa/configure/) 4. Initialize the Apple Login in your app. Note I am using Vue as my framework, the exact implementation will vary depending on the framework of your choice ```ts // onMounted is vue specific onMounted(() => { SocialLogin.initialize({ apple: {} }) }); ``` 5. Create a button that will begin the login process. Said button should call the following function: ```ts async function loginApple() { const res = await SocialLogin.login({ provider: 'apple', options: {} }) ``` 6. Run your app on a ***PHYSICAL*** device and test it. If you followed the steps closely you will see the following screen after clicking your button. ![Apple Sign In prompt on iOS device](/social-login-assets/apple-sign-in-ios-final.png) That’s it! You are all set. # Apple login for web browsers > This guide provides a detailed walkthrough on setting up Apple Login using Capacitor for web applications, utilizing the @capgo/capacitor-social-login plugin to ensure a seamless integration process. Configuring the web login is not trivial. It’s more difficult than setting up `Sign in with Apple` on iOS but more difficult than setting up `Sign in with Apple` on Android. ## Generating the service [Section titled “Generating the service”](#generating-the-service) Note This step is redundant if you have already configured `Sign in with Apple` on Android. Please follow the guide [here](/docs/plugins/social-login/apple/android/#creating-the-service-id/) to generate the service. ## Configuring the `Return URLs` [Section titled “Configuring the Return URLs”](#configuring-the-return-urls) 1. **Go to your Service ID configuration** In the [Apple Developer Portal](https://developer.apple.com), navigate to `Identifiers` > `Services IDs` and click on your service ID. 2. **Configure Sign in with Apple** Click on `Configure` next to `Sign in with Apple`. ![apple\_dev\_configure\_login](/social-login-assets/apple_dev_configure_login.webp) 3. **Add the Return URLs** Click on the `+` button to add a new return URL. ![apple\_dev\_return\_url\_plus](/social-login-assets/apple_dev_return_url_plus.webp) 4. **Add the Return URLs** Add your domain for your web application in `Domains and Subdomains`. Caution You **CANNOT** add `localhost` or `127.0.0.1` as a domain here. Then, add your domain with the `https://` prefix and the path from which you will call Apple Login. For example, if your domain is `https://my-app.com` and you will call Apple Login from `/login`, you should add `https://my-app.com/login` as the return URL. Caution You **MUST** add both the domain with a trailing slash and without a trailing slash. ![apple\_dev\_return\_url\_add](/social-login-assets/apple_dev_return_url_add.webp) 5. **Save the changes** 1. Click on the `Next` button to save the changes. 2. Click on the `Save` button to save the changes. 6. You should be ready to test the login for JavaScript. Please note that you cannot test from localhost. # Better Auth Integration > Use @capgo/capacitor-social-login with Better Auth for native Google, Apple, and Facebook sign-in, plus Generic OAuth providers. ## Overview [Section titled “Overview”](#overview) Better Auth works well with `@capgo/capacitor-social-login` when you want native sign-in on the device but still want Better Auth to create and manage the session on your backend. This page focuses on the two integration patterns that fit best: * Native token handoff for Google, Apple, and Facebook * Better Auth Generic OAuth for providers like Auth0, Okta, Keycloak, and custom OIDC servers ## Which pattern to use [Section titled “Which pattern to use”](#which-pattern-to-use) ### Use native token handoff [Section titled “Use native token handoff”](#use-native-token-handoff) Use `SocialLogin.login()` first, then send the returned token to Better Auth with `authClient.signIn.social()` when you use: * Google * Apple * Facebook ### Use Better Auth Generic OAuth [Section titled “Use Better Auth Generic OAuth”](#use-better-auth-generic-oauth) Let Better Auth own the full OAuth redirect flow when you use: * Auth0 * Okta * Keycloak * GitHub * OneLogin * Any custom OAuth2 or OIDC provider That keeps the session exchange on the Better Auth side and avoids duplicating redirect logic between two systems. ## Better Auth server setup [Section titled “Better Auth server setup”](#better-auth-server-setup) Start by configuring Better Auth with the social providers you want to support: ```typescript import { betterAuth } from 'better-auth'; export const auth = betterAuth({ baseURL: process.env.BETTER_AUTH_URL, socialProviders: { google: { clientId: process.env.GOOGLE_CLIENT_ID as string, clientSecret: process.env.GOOGLE_CLIENT_SECRET as string, }, apple: { clientId: process.env.APPLE_CLIENT_ID as string, clientSecret: process.env.APPLE_CLIENT_SECRET as string, appBundleIdentifier: process.env.APPLE_APP_BUNDLE_IDENTIFIER as string, }, facebook: { clientId: process.env.FACEBOOK_CLIENT_ID as string, clientSecret: process.env.FACEBOOK_CLIENT_SECRET as string, }, }, trustedOrigins: ['https://appleid.apple.com'], }); ``` Note For Apple on native iOS, Better Auth documents that you should provide `appBundleIdentifier` so the Apple ID token audience matches the bundle identifier used by iOS. ## Better Auth client setup [Section titled “Better Auth client setup”](#better-auth-client-setup) ```typescript import { createAuthClient } from 'better-auth/client'; export const authClient = createAuthClient({ baseURL: 'https://auth.example.com', }); ``` If you use React, use the Better Auth React client package your app already uses. The token handoff pattern stays the same. ## Google example [Section titled “Google example”](#google-example) This is the cleanest integration path for native mobile Google sign-in: ```typescript import { SocialLogin } from '@capgo/capacitor-social-login'; import { authClient } from '@/lib/auth-client'; const googleResult = await SocialLogin.login({ provider: 'google', options: { scopes: ['profile', 'email'], }, }); if (googleResult.result.responseType !== 'online' || !googleResult.result.idToken) { throw new Error('Google online mode with idToken is required for Better Auth.'); } await authClient.signIn.social({ provider: 'google', idToken: { token: googleResult.result.idToken, accessToken: googleResult.result.accessToken?.token, }, callbackURL: '/dashboard', }); ``` ## Apple example [Section titled “Apple example”](#apple-example) For Apple, pass the same nonce to both the native login request and Better Auth: ```typescript import { SocialLogin } from '@capgo/capacitor-social-login'; import { authClient } from '@/lib/auth-client'; const nonce = crypto.randomUUID(); const appleResult = await SocialLogin.login({ provider: 'apple', options: { scopes: ['email', 'name'], nonce, }, }); if (!appleResult.result.idToken) { throw new Error('Apple idToken is required for Better Auth.'); } await authClient.signIn.social({ provider: 'apple', idToken: { token: appleResult.result.idToken, nonce, accessToken: appleResult.result.accessToken?.token, }, callbackURL: '/dashboard', }); ``` ## Facebook example [Section titled “Facebook example”](#facebook-example) Better Auth documents two Facebook handoff modes: * iOS Limited Login: pass the `idToken` * Access-token flow: pass the access token as both `token` and `accessToken` This works with the response shape from `@capgo/capacitor-social-login`: ```typescript import { SocialLogin } from '@capgo/capacitor-social-login'; import { authClient } from '@/lib/auth-client'; const facebookResult = await SocialLogin.login({ provider: 'facebook', options: { permissions: ['email', 'public_profile'], }, }); const betterAuthToken = facebookResult.result.idToken ? { token: facebookResult.result.idToken, } : facebookResult.result.accessToken?.token ? { token: facebookResult.result.accessToken.token, accessToken: facebookResult.result.accessToken.token, } : null; if (!betterAuthToken) { throw new Error('Facebook idToken or access token is required for Better Auth.'); } await authClient.signIn.social({ provider: 'facebook', idToken: betterAuthToken, callbackURL: '/dashboard', }); ``` ## Generic OAuth providers with Better Auth [Section titled “Generic OAuth providers with Better Auth”](#generic-oauth-providers-with-better-auth) For Auth0, Okta, Keycloak, GitHub, Microsoft Entra ID, and similar providers, Better Auth’s Generic OAuth plugin is usually the better fit than passing tokens from `SocialLogin.login({ provider: 'oauth2' })`. ### Better Auth server [Section titled “Better Auth server”](#better-auth-server) ```typescript import { betterAuth } from 'better-auth'; import { genericOAuth } from 'better-auth/plugins'; export const auth = betterAuth({ plugins: [ genericOAuth({ config: [ { providerId: 'keycloak', discoveryUrl: 'https://sso.example.com/realms/mobile/.well-known/openid-configuration', clientId: process.env.KEYCLOAK_CLIENT_ID as string, clientSecret: process.env.KEYCLOAK_CLIENT_SECRET as string, }, ], }), ], }); ``` ### Better Auth client [Section titled “Better Auth client”](#better-auth-client) ```typescript import { createAuthClient } from 'better-auth/client'; import { genericOAuthClient } from 'better-auth/client/plugins'; export const authClient = createAuthClient({ baseURL: 'https://auth.example.com', plugins: [genericOAuthClient()], }); await authClient.signIn.oauth2({ providerId: 'keycloak', callbackURL: '/dashboard', }); ``` ## Provider examples for Better Auth Generic OAuth [Section titled “Provider examples for Better Auth Generic OAuth”](#provider-examples-for-better-auth-generic-oauth) Better Auth ships pre-configured helpers for several providers. These are the closest match to the extra provider examples you see in the social-login plugin docs. ### Auth0 [Section titled “Auth0”](#auth0) ```typescript import { betterAuth } from 'better-auth'; import { auth0, genericOAuth } from 'better-auth/plugins'; export const auth = betterAuth({ plugins: [ genericOAuth({ config: [ auth0({ providerId: 'auth0', domain: 'dev-example.eu.auth0.com', clientId: process.env.AUTH0_CLIENT_ID as string, clientSecret: process.env.AUTH0_CLIENT_SECRET as string, scopes: ['openid', 'profile', 'email', 'offline_access'], }), ], }), ], }); ``` ```typescript await authClient.signIn.oauth2({ providerId: 'auth0', callbackURL: '/dashboard', }); ``` ### Microsoft Entra ID [Section titled “Microsoft Entra ID”](#microsoft-entra-id) ```typescript import { betterAuth } from 'better-auth'; import { genericOAuth, microsoftEntraId } from 'better-auth/plugins'; export const auth = betterAuth({ plugins: [ genericOAuth({ config: [ microsoftEntraId({ providerId: 'entra', tenantId: 'common', clientId: process.env.AZURE_CLIENT_ID as string, clientSecret: process.env.AZURE_CLIENT_SECRET as string, scopes: ['openid', 'profile', 'email', 'User.Read'], }), ], }), ], }); ``` ```typescript await authClient.signIn.oauth2({ providerId: 'entra', callbackURL: '/dashboard', }); ``` ### Okta [Section titled “Okta”](#okta) ```typescript import { betterAuth } from 'better-auth'; import { genericOAuth, okta } from 'better-auth/plugins'; export const auth = betterAuth({ plugins: [ genericOAuth({ config: [ okta({ providerId: 'okta', issuer: 'https://dev-12345.okta.com/oauth2/default', clientId: process.env.OKTA_CLIENT_ID as string, clientSecret: process.env.OKTA_CLIENT_SECRET as string, scopes: ['openid', 'profile', 'email', 'offline_access'], }), ], }), ], }); ``` ```typescript await authClient.signIn.oauth2({ providerId: 'okta', callbackURL: '/dashboard', }); ``` ### Keycloak [Section titled “Keycloak”](#keycloak) ```typescript import { betterAuth } from 'better-auth'; import { genericOAuth, keycloak } from 'better-auth/plugins'; export const auth = betterAuth({ plugins: [ genericOAuth({ config: [ keycloak({ providerId: 'keycloak', issuer: 'https://sso.example.com/realms/mobile', clientId: process.env.KEYCLOAK_CLIENT_ID as string, clientSecret: process.env.KEYCLOAK_CLIENT_SECRET as string, scopes: ['openid', 'profile', 'email', 'offline_access'], }), ], }), ], }); ``` ```typescript await authClient.signIn.oauth2({ providerId: 'keycloak', callbackURL: '/dashboard', }); ``` ### GitHub with manual Generic OAuth config [Section titled “GitHub with manual Generic OAuth config”](#github-with-manual-generic-oauth-config) GitHub does not have a Better Auth helper on the Generic OAuth page, so use manual configuration: ```typescript import { betterAuth } from 'better-auth'; import { genericOAuth } from 'better-auth/plugins'; export const auth = betterAuth({ plugins: [ genericOAuth({ config: [ { providerId: 'github', clientId: process.env.GITHUB_CLIENT_ID as string, clientSecret: process.env.GITHUB_CLIENT_SECRET as string, authorizationUrl: 'https://github.com/login/oauth/authorize', tokenUrl: 'https://github.com/login/oauth/access_token', userInfoUrl: 'https://api.github.com/user', scopes: ['read:user', 'user:email'], pkce: true, }, ], }), ], }); ``` ```typescript await authClient.signIn.oauth2({ providerId: 'github', callbackURL: '/dashboard', }); ``` ## Notes and caveats [Section titled “Notes and caveats”](#notes-and-caveats) 1. **Use Google online mode** Better Auth needs the `idToken`, so `google.mode: 'offline'` is not the right fit for this handoff flow. 2. **Reuse the Apple nonce** Generate it once, send it to Apple native login, then send the same value to Better Auth. 3. **Handle Facebook differently by platform** Limited Login on iOS gives you an ID token. Other flows may only give an access token. 4. **Do not mix Generic OAuth flows unless you have a reason** If Better Auth owns the OAuth provider configuration, let Better Auth own the redirect flow too. ## Further reading [Section titled “Further reading”](#further-reading) * [Better Auth Google provider docs](https://better-auth.com/docs/authentication/google) * [Better Auth Apple provider docs](https://better-auth.com/docs/authentication/apple) * [Better Auth Facebook provider docs](https://better-auth.com/docs/authentication/facebook) * [Better Auth Generic OAuth plugin docs](https://better-auth.com/docs/plugins/generic-oauth) * [Social Login OAuth2 and OIDC providers](/docs/plugins/social-login/oauth2/) # Facebook Login Setup > This guide provides a comprehensive walkthrough on setting up Facebook Login using Capacitor, ensuring seamless integration and enhanced user authentication for your application. ## Introduction [Section titled “Introduction”](#introduction) In this guide, you will learn how to setup Facebook Login with Capgo Social Login. You will need the following: * A Facebook Developer Account * Your app’s package name/bundle ID * Access to a terminal for generating key hashes (Android) ## General Setup [Section titled “General Setup”](#general-setup) If you don’t already have a Facebook app created, follow these steps: 1. Create a Facebook App Follow the tutorial to [Create an App](https://developers.facebook.com/docs/development/create-an-app/) 2. Add Facebook Login to your app In your Facebook Developer Dashboard, add the Facebook Login product to your app 3. Before you can release your app to the public, follow this [tutorial](https://developers.facebook.com/docs/development/release/) to publish it ## Important Information [Section titled “Important Information”](#important-information) Here’s where to find the key information you’ll need for integration: 1. `CLIENT_TOKEN`: ![Facebook developer dashboard showing where to find the client token](/social-login-assets/fb_where_to_fiind_client_token.png) 2. `APP_ID`: ![Facebook developer dashboard showing where to find the app ID](/social-login-assets/fb_where_to_find_app_id.png) 3. `APP_NAME`: ![Facebook developer dashboard showing where to find the app name](/social-login-assets/fb_where_to_find_app_name.png) ## Android Setup [Section titled “Android Setup”](#android-setup) 1. Add internet permission to your `AndroidManifest.xml` Ensure this line is present: ```xml <uses-permission android:name="android.permission.INTERNET"/> ``` 2. Generate your Android key hash This is a crucial security step required by Facebook. Open your terminal and run: ```bash keytool -exportcert -alias androiddebugkey -keystore ~/.android/debug.keystore | openssl sha1 -binary | openssl base64 -A ``` When prompted for a password, use: `android` Note For release builds, you’ll need to use your release keystore: ```bash keytool -exportcert -alias your-key-name -keystore your-keystore-path | openssl sha1 -binary | openssl base64 -A ``` 3. Add the key hash to your Facebook app 1. Go to your app’s dashboard on Facebook Developers 2. Navigate to Settings > Basic 3. Scroll down to “Android” section 4. Click “Add Platform” if Android isn’t added yet and fill in the details 5. Add the key hash you generated 6. For production, add both debug and release key hashes 4. Update your `AndroidManifest.xml` to include: ```xml <application> ... <activity android:name="com.facebook.FacebookActivity" android:configChanges="keyboard|keyboardHidden|screenLayout|screenSize|orientation" android:label="@string/app_name" /> <activity android:name="com.facebook.CustomTabActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="FB[APP_ID]" /> </intent-filter> </activity> </application> ``` Caution Make sure to replace `[APP_ID]` with your actual Facebook app ID in the `android:scheme` attribute ## iOS Setup [Section titled “iOS Setup”](#ios-setup) 1. Add the iOS platform in Facebook Developer Console 1. Go to your app’s dashboard on Facebook Developers 2. Navigate to Settings > Basic 3. Scroll down to very bottom of the page and click “Add Platform” 4. Select iOS and fill in the required details 2. Open your Xcode project and navigate to Info.plist 3. Add the following entries to your Info.plist: ```xml <key>FacebookAppID</key> <string>[APP-ID]</string> <key>FacebookClientToken</key> <string>[CLIENT-TOKEN]</string> <key>FacebookDisplayName</key> <string>[APP-NAME]</string> <key>LSApplicationQueriesSchemes</key> <array> <string>fbapi</string> <string>fb-messenger-share-api</string> </array> <key>CFBundleURLTypes</key> <array> <dict> <key>CFBundleURLSchemes</key> <array> <string>fb[APP-ID]</string> </array> </dict> </array> ``` Caution Replace the following values: * `[APP-ID]` with your Facebook app ID * `[CLIENT-TOKEN]` with your client token * `[APP-NAME]` with your app’s name 4. Modify the `AppDelegate.swift` ```swift import FBSDKCoreKit @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. // Initialize Facebook SDK FBSDKCoreKit.ApplicationDelegate.shared.application( application, didFinishLaunchingWithOptions: launchOptions ) return true } func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool { // Called when the app was launched with a url. Feel free to add additional processing here, // but if you want the App API to support tracking app url opens, make sure to keep this call if (FBSDKCoreKit.ApplicationDelegate.shared.application( app, open: url, sourceApplication: options[UIApplication.OpenURLOptionsKey.sourceApplication] as? String, annotation: options[UIApplication.OpenURLOptionsKey.annotation] )) { return true; } else { return ApplicationDelegateProxy.shared.application(app, open: url, options: options) } } } ``` ## Using Facebook Login in Your App [Section titled “Using Facebook Login in Your App”](#using-facebook-login-in-your-app) Caution **Before You Start**: Remember that with the new Facebook SDK, the token type you receive depends entirely on the user’s App Tracking choice, not on your code configuration. Always implement both access token and JWT token handling in your backend to ensure authentication works for all users. 1. Initialize the Facebook login in your app ```typescript import { SocialLogin } from '@capgo/capacitor-social-login'; // Initialize during app startup await SocialLogin.initialize({ facebook: { appId: 'APP_ID', clientToken: 'CLIENT_TOKEN', } }) ``` 2. Implement the login function ```typescript async function loginWithFacebook() { try { const result = await SocialLogin.login({ provider: 'facebook', options: { permissions: ['email', 'public_profile'], limitedLogin: false // See Limited Login section below for important details } }); console.log('Facebook login result:', result); // Handle successful login } catch (error) { console.error('Facebook login error:', error); // Handle error } } ``` Note **Limited Login (iOS Only)**: Set `limitedLogin` to true if you want to use Facebook’s Limited Login feature. This is an iOS-only feature that provides enhanced privacy by restricting the data shared during login. **Important Limitations:** * **iOS Only**: Limited Login only affects iOS devices and has no impact on Android * **ATT Override**: Even if you set `limitedLogin: false`, Facebook will automatically force it to `true` if the user hasn’t granted App Tracking Transparency (ATT) permission * **Always Handle Both Cases**: Your app should always be prepared to handle both limited and full login scenarios **Checking ATT Status:** ```typescript // Check if user has granted tracking permission const trackingStatus = await SocialLogin.providerSpecificCall({ call: 'facebook#requestTracking', options: {} }); console.log('Tracking status:', trackingStatus.status); // 'authorized', 'denied', 'notDetermined', or 'restricted' ``` **Recommended Implementation if access\_token is preferred:** ```typescript async function loginWithFacebook() { try { // Check ATT status first const trackingStatus = await SocialLogin.providerSpecificCall({ call: 'facebook#requestTracking', options: {} }); const result = await SocialLogin.login({ provider: 'facebook', options: { permissions: ['email', 'public_profile'], limitedLogin: trackingStatus.status === 'denied' // Auto-adjust based on ATT } }); // Handle different response types based on limited login if (result.result.accessToken) { // Your app logic should work with both limited and full login console.log('Login successful:', result); } } catch (error) { console.error('Facebook login error:', error); } } ``` **What Happens in Limited Login:** * **Reduced Data Access**: Some user data may not be available * **Different Token Types**: Access tokens may have different capabilities * **Privacy Compliance**: Helps comply with iOS privacy requirements **Important**: Always test your app with both limited and full login scenarios to ensure your app works correctly in both cases. You can learn more about Limited Login [here](https://developers.facebook.com/docs/facebook-login/limited-login/). 3. **Get User Profile Data** After successful login, you can retrieve additional profile information: ```typescript async function getFacebookProfile() { try { const profileResponse = await SocialLogin.providerSpecificCall({ call: 'facebook#getProfile', options: { fields: ['id', 'name', 'email', 'first_name', 'last_name', 'picture'] } }); console.log('Facebook profile:', profileResponse.profile); return profileResponse.profile; } catch (error) { console.error('Failed to get Facebook profile:', error); return null; } } // Example usage after login async function loginAndGetProfile() { const loginResult = await loginWithFacebook(); if (loginResult) { const profile = await getFacebookProfile(); if (profile) { console.log('User ID:', profile.id); console.log('Name:', profile.name); console.log('Email:', profile.email); console.log('Profile Picture:', profile.picture?.data?.url); } } } ``` Tip **Available Profile Fields**: You can request any fields available in Facebook’s Graph API. Common fields include: `id`, `name`, `email`, `first_name`, `last_name`, `picture`, `birthday`, `gender`, `location`, `hometown`. Note that some fields may require additional permissions. **Token Type Limitation**: The `getProfile` call only works when you have an **access token** (standard login with tracking allowed). If the user denied tracking or you’re using limited login (JWT token only), this call will fail. In that case, use the profile data provided in the initial login response. ## ⚠️ Critical: Backend Token Handling [Section titled “⚠️ Critical: Backend Token Handling”](#️-critical-backend-token-handling) Danger **CRITICAL iOS BEHAVIOR**: Limited Login and App Tracking Transparency (ATT) are **iOS-ONLY** features. On Android, you will always receive access tokens regardless of the `limitedLogin` setting. **iOS Token Behavior**: * **`limitedLogin: true`** → Always JWT token (iOS only) * **`limitedLogin: false` + User ALLOWS tracking** → Access token * **`limitedLogin: false` + User DENIES tracking** → JWT token (iOS automatically overrides your setting) **Android Token Behavior**: Always access token, `limitedLogin` setting is ignored. Your backend must handle **two different token types** because iOS users can receive either access tokens or JWT tokens depending on their App Tracking Transparency choice, while Android users always receive access tokens. ### Token Types by Platform [Section titled “Token Types by Platform”](#token-types-by-platform) | Platform | limitedLogin Setting | User ATT Choice | Result Token Type | | ----------- | -------------------- | --------------- | ------------------------- | | **iOS** | `true` | Any | JWT Token | | **iOS** | `false` | Allows tracking | Access Token | | **iOS** | `false` | Denies tracking | JWT Token (auto-override) | | **Android** | Any | N/A | Access Token (always) | ### Backend Implementation [Section titled “Backend Implementation”](#backend-implementation) 1. **Detect Token Type and Handle Accordingly** ```typescript async function loginWithFacebook() { try { const loginResult = await SocialLogin.login({ provider: 'facebook', options: { permissions: ['email', 'public_profile'], limitedLogin: false // iOS: depends on ATT, Android: ignored } }); if (loginResult.accessToken) { // Access token (Android always, iOS when tracking allowed) return handleAccessToken(loginResult.accessToken.token); } else if (loginResult.idToken) { // JWT token (iOS only when tracking denied or limitedLogin: true) return handleJWTToken(loginResult.idToken); } } catch (error) { console.error('Facebook login error:', error); } } ``` 2. **Firebase Integration Example** ```typescript import { OAuthProvider, FacebookAuthProvider, signInWithCredential } from 'firebase/auth'; async function handleAccessToken(accessToken: string, nonce: string) { // For access tokens, use OAuthProvider (new method) const fbOAuth = new OAuthProvider("facebook.com"); const credential = fbOAuth.credential({ idToken: accessToken, rawNonce: nonce }); try { const userResponse = await signInWithCredential(auth, credential); return userResponse; } catch (error) { console.error('Firebase OAuth error:', error); return false; } } async function handleJWTToken(jwtToken: string) { // For JWT tokens, send to your backend for validation try { const response = await fetch('/api/auth/facebook-jwt', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ jwtToken }) }); const result = await response.json(); return result; } catch (error) { console.error('JWT validation error:', error); return false; } } ``` 3. **Backend JWT Validation** ```typescript // Backend: Validate JWT token from Facebook import jwt from 'jsonwebtoken'; import { Request, Response } from 'express'; app.post('/api/auth/facebook-jwt', async (req: Request, res: Response) => { const { jwtToken } = req.body; try { // Verify JWT token with Facebook's public key // See: https://developers.facebook.com/docs/facebook-login/limited-login/token/validating/#standard-claims const decoded = jwt.verify(jwtToken, getFacebookPublicKey(), { algorithms: ['RS256'], audience: process.env.FACEBOOK_APP_ID, issuer: 'https://www.facebook.com' // From: https://www.facebook.com/.well-known/openid-configuration/?_rdr }); // Extract user info from JWT const userInfo = { id: decoded.sub, email: decoded.email, name: decoded.name, isJWTAuth: true }; // Create your app's session/token const sessionToken = createUserSession(userInfo); res.json({ success: true, token: sessionToken, user: userInfo }); } catch (error) { console.error('JWT validation failed:', error); res.status(401).json({ success: false, error: 'Invalid token' }); } }); ``` 4. **Generic Backend Token Handler** ```typescript // Handle both token types in your backend async function authenticateFacebookUser(tokenData: any) { if (tokenData.accessToken) { // Handle access token - validate with Facebook Graph API const response = await fetch(`https://graph.facebook.com/me?access_token=${tokenData.accessToken}&fields=id,name,email`); const userInfo = await response.json(); return { user: userInfo, tokenType: 'access_token', expiresIn: tokenData.expiresIn || 3600 }; } else if (tokenData.jwtToken) { // Handle JWT token - decode and validate // See: https://developers.facebook.com/docs/facebook-login/limited-login/token/validating/#standard-claims const decoded = jwt.verify(tokenData.jwtToken, getFacebookPublicKey()); return { user: { id: decoded.sub, name: decoded.name, email: decoded.email }, tokenType: 'jwt', expiresIn: decoded.exp - Math.floor(Date.now() / 1000) }; } else { throw new Error('No valid token provided'); } } ``` ### Key Considerations [Section titled “Key Considerations”](#key-considerations) Danger **Critical iOS-Only Understanding**: * **iOS**: User’s App Tracking choice determines token type, NOT your code settings (even when `limitedLogin: false`) * **Android**: Always receives access tokens, regardless of `limitedLogin` setting * **Limited Login is iOS-ONLY** - Android ignores this setting completely **Access Token (Standard Login)**: * ✅ **Android**: Always available (iOS-only restrictions don’t apply) * ✅ **iOS**: Only when user explicitly allows app tracking * ✅ Can be used to access Facebook Graph API * ✅ Longer expiration times * ✅ More user data available * ❌ **Becoming less common on iOS** as users increasingly deny tracking **JWT Token (iOS-Only Privacy Mode)**: * ❌ **Android**: Never occurs (not supported) * ✅ **iOS**: When tracking denied or `limitedLogin: true` * ✅ Respects iOS user privacy preferences * ❌ Contains basic user info only * ❌ Shorter expiration times * ❌ No access to Facebook Graph API * ⚠️ **Now the most common scenario for iOS users** **Platform-Specific Behavior**: * **iOS apps**: Must handle both access tokens AND JWT tokens * **Android apps**: Only need to handle access tokens * **Cross-platform apps**: Must implement both token handling methods Tip **Essential for iOS**: You MUST implement both token handling methods. Many iOS developers assume they’ll always get access tokens and their apps break when users deny tracking. ## Secure Context Requirements (Web/Capacitor) [Section titled “Secure Context Requirements (Web/Capacitor)”](#secure-context-requirements-webcapacitor) ### Crypto API Limitations [Section titled “Crypto API Limitations”](#crypto-api-limitations) The updated Facebook login flow requires the **Web Crypto API** for nonce generation, which is only available in **secure contexts**: ```typescript // This requires secure context (HTTPS or localhost) async function sha256(message: string) { const msgBuffer = new TextEncoder().encode(message); const hashBuffer = await crypto.subtle.digest("SHA-256", msgBuffer); // ❌ Fails in insecure context // ... } ``` ### Development Environment Issues [Section titled “Development Environment Issues”](#development-environment-issues) **Common Problem**: `ionic serve` with HTTP URLs breaks Facebook authentication | Environment | Crypto API Available | Facebook Login Works | | --------------------------- | -------------------- | -------------------- | | `http://localhost:3000` | ✅ Yes | ✅ Yes | | `http://127.0.0.1:3000` | ✅ Yes | ✅ Yes | | `http://192.168.1.100:3000` | ❌ No | ❌ No | | `https://any-domain.com` | ✅ Yes | ✅ Yes | ### Solutions for Capacitor Development [Section titled “Solutions for Capacitor Development”](#solutions-for-capacitor-development) 1. **Use localhost for web testing** ```bash # Instead of ionic serve --host=0.0.0.0 ionic serve --host=localhost ``` 2. **Enable HTTPS in Ionic** ```bash ionic serve --ssl ``` 3. **Test on actual devices** ```bash # Capacitor apps run in secure context on devices ionic cap run ios ionic cap run android ``` 4. **Alternative nonce generation for development** ```typescript async function generateNonce() { if (typeof crypto !== 'undefined' && crypto.subtle) { // Secure context - use crypto.subtle return await sha256(Math.random().toString(36).substring(2, 10)); } else { // Fallback for development (not secure for production) console.warn('Using fallback nonce - not secure for production'); return btoa(Math.random().toString(36).substring(2, 10)); } } ``` ### Firebase Integration Note [Section titled “Firebase Integration Note”](#firebase-integration-note) Recent Firebase documentation requires JWT tokens with nonces for Facebook authentication, regardless of login settings. This approach works with both `limitedLogin: true` and `limitedLogin: false`: ```typescript // Both modes can return JWT tokens depending on user choice const loginResult = await SocialLogin.login({ provider: 'facebook', options: { permissions: ['email', 'public_profile'], limitedLogin: false, // true = always JWT, false = depends on user tracking choice nonce: nonce } }); ``` **Development Limitation**: If you’re using `ionic serve` on a network IP (not localhost), Facebook login will fail due to crypto API restrictions. Use localhost or HTTPS for web testing. Tip **Production Safety**: Capacitor apps on iOS/Android always run in secure contexts, so this limitation only affects web development environments. ## Troubleshooting [Section titled “Troubleshooting”](#troubleshooting) ### Common Issues and Solutions [Section titled “Common Issues and Solutions”](#common-issues-and-solutions) 1. **Key hash errors on Android** * Double check that you’ve added the correct key hash to the Facebook dashboard * For release builds, make sure you’ve added both debug and release key hashes * Verify you’re using the correct keystore when generating the hash 2. **Facebook login button doesn’t appear** * Verify all manifest entries are correct * Check that your Facebook App ID and Client Token are correct * Ensure you’ve properly initialized the SDK 3. **Common iOS issues** * Make sure all Info.plist entries are correct * Verify URL schemes are properly configured * Check that your bundle ID matches what’s registered in the Facebook dashboard ### Testing [Section titled “Testing”](#testing) 1. **Before testing, add test users in the Facebook Developer Console** * Go to Roles > Test Users * Create a test user * Use these credentials for testing 2. **Test both debug and release builds** * Debug build with debug key hash * Release build with release key hash * Test on both emulator and physical devices Remember to test the full login flow, including: * Successful login * Login cancellation * Error handling * Logout functionality # Firebase Google Login on Android > Learn how to set up Google Sign-In with Firebase Authentication on Android using the Capacitor Social Login plugin. ## Introduction [Section titled “Introduction”](#introduction) This guide will help you integrate Google Sign-In with Firebase Authentication on Android. I assume you have already completed the [general Firebase Google setup](/docs/plugins/social-login/firebase/google/general/) Note I will assume that you have not yet created your Android app in the Firebase Console. If you have, your steps will be slightly different. ## Setup Steps [Section titled “Setup Steps”](#setup-steps) 1. Go to your project overview over at [console.cloud.google.com](https://console.cloud.google.com/) ![Firebase Project Overview](/social-login-assets/firebase_project_overview.webp) 2. Click on the `Add app` button ![Firebase Add App Button](/social-login-assets/firebase_project_add_app.webp) Note It is possible that you will have to look here for this button. This applies only if you have already created a different app in the Firebase Console. ![Firebase Add App Button](/social-login-assets/firebase_project_add_app_2.webp) 3. Select `Android` ![Firebase Add App Android Button](/social-login-assets/firebase_project_add_app_android.webp) 4. Fill the first part of the form 1. Fill the `Android package name` 1. Open Android Studio at your app using `npx cap open android` 2. At the very bottom of the navigator, find the `Gradle Scripts` ![Gradle Scripts section in Android Studio project navigator](/social-login-assets/studio_gradle_scripts.png) 3. Find `build.gradle` for the module `app` ![build.gradle (Module: app) file in Gradle Scripts section](/social-login-assets/studio_build_gradle.png) 4. Copy the `android.defaultConfig.applicationId`. This will be your `package name` in the Firebase console ![Build.gradle file showing applicationId configuration](/social-login-assets/studio_build_gradle_app_id.png) Note The ID shown here will differ from the one I will use for the rest of the guide. I will use `app.capgo.plugin.SocialLogin` for the rest of the guide. 5. Paste it in the Firebase console ![Firebase Add App Android Package Name Field](/social-login-assets/firebase_project_add_app_android_package_name.webp) 2. Click on the `Register app` button ![Firebase Add App Android Register Button](/social-login-assets/firebase_project_add_app_android_register.webp) 5. Skip the `Download and then add config file` step ![Firebase Add App Android Skip 'Download and then add config file'](/social-login-assets/firebase_project_add_app_android_skip_download.webp) 6. Skip the `Add firebase SDK` step ![Firebase Add App Android Skip 'Add firebase SDK'](/social-login-assets/firebase_project_add_app_android_skip_download_firebase_sdk.webp) 7. Click on the `Continue to console` button ![Firebase Add App Android Continue to Console Button](/social-login-assets/firebase_project_add_app_android_continue_to_console.webp) 8. If you do not get automatically authenticated, go to `settings` -> `general` -> `your apps` -> find your android app and click on it ![Firebase Add App Android Settings General Your Apps Button](/social-login-assets/firebase_project_add_app_android_settings_general_your_apps.webp) 9. Get your SHA1 fingerprint Follow steps 10-11 from the [Google Login Android setup guide](/docs/plugins/social-login/google/android/#using-google-login-on-android): 1. Now, open the terminal. Make sure that you are in the `android` folder of your app and run `./gradlew signInReport` ![Terminal showing gradlew signInReport command](/social-login-assets/term_sign_report.png) 2. Scroll to the top of this command. You should see the following. Copy the `SHA1`. ![Terminal output showing SHA1 certificate fingerprint](/social-login-assets/term_sign_report_res.png) Note I will use a slightly different SHA1 for the rest of the guide, because I have changed computes since writing the original Google login android setup guide. Caution The SHA1 is very important to get right. If you mess up, the authentication will fail in strange ways. Please ****[READ THE GOOGLE LOGIN ANDROID SETUP GUIDE](/docs/plugins/social-login/google/android/#using-google-login-on-android)**** to get it right. 10. Add the SHA1 to the Firebase project 1. Click on the `Add fingerprint` button ![Firebase Add App Android Add Fingerprint Button](/social-login-assets/firebase_project_add_app_android_add_fingerprint.webp) 2. Paste the SHA1 you copied in the previous step ![Firebase Add App Android Add Fingerprint SHA1 Field](/social-login-assets/firebase_project_add_app_android_add_fingerprint_sha1.webp) 3. Click on the `Save` button ![Firebase Add App Android Add Fingerprint Save Button](/social-login-assets/firebase_project_add_app_android_add_fingerprint_add.webp) 11. Get your web client ID 1. Go to `Build` -> `Authentication` ![Firebase Authentication Menu](/social-login-assets/firebase_select_authentication.webp) 2. Click on the `Sign-in method` button ![Firebase Authentication Sign-in Method Button](/social-login-assets/firebase_select_authentication_sign_in_method.webp) 3. Click on the `Google` provider ![Firebase Authentication Sign-in Method Google Provider](/social-login-assets/firebase_select_authentication_sign_in_method_google.webp) 4. Click on the `Web SDK configuration` button ![Firebase Authentication Sign-in Method Web SDK Configuration Button](/social-login-assets/firebase_select_authentication_sign_in_method_web_sdk_configuration.webp) 5. Copy the `Web client ID`. This will be your `webClientId` in the `initialize` method of the plugin. ![Firebase Authentication Sign-in Method Web SDK Configuration Web Client ID](/social-login-assets/firebase_select_authentication_sign_in_method_web_sdk_configuration_web_client_id.webp) 12. Use the web client ID in JS. Note I recommend using the `authenticateWithGoogle` helper function available in the [authUtils.ts](https://github.com/Cap-go/capacitor-social-login/blob/main/example-app/src/authUtils.ts) file of the example app. At this point, you are ****TECHNICALLY**** ready to use Google Sign-In with Firebase Authentication on Android. However, I would recommend double-checking the setup in the Google Cloud console as explained in the next step. ## Double-check the setup in Google Cloud console [Section titled “Double-check the setup in Google Cloud console”](#double-check-the-setup-in-google-cloud-console) In order to make sure that the setup is correct, you should double-check the setup in the Google Cloud console. 1. Go to [console.cloud.google.com](https://console.cloud.google.com/) 2. Find your project 1. Click on the project selector ![Google Cloud Console Project Selector](/social-login-assets/firebase_double_check_gc_project_select.webp) 2. Search up your project by the exact name of your Firebase project and click on it. In my case, it is `sociallogin-tutorial-app`. ![Firebase Project Selector Project](/social-login-assets/firebase_gc_project_select_project.webp) 3. Open the search bar and open `credentials` 1. Open the search bar ![Google Cloud Console Search Bar](/social-login-assets/firebase_double_check_gc_search_bar.webp) 2. Search for `credentials` and click on the `APIs and Services` one (number 2 on the screenshot) ![Google Cloud Console Credentials Search](/social-login-assets/firebase_gc_credentials_search.webp) 4. Verify that you see both the Android and Web client IDs in the list. ![Google Cloud Console Credentials List](/social-login-assets/firebase_gc_credentials_list.webp) Caution If you do not see both the Android and Web client IDs in the list, you have made a mistake in the setup. Please go back and check your steps. It is also possible, and it has happened to me, that you already have added the Android SHA1 hash with the same app ID in a different project. This will result in Firbase being unable to create an Android client ID. In this case, you will need to remove the SHA1 from the other project as well as on Firebase (using the Firebase console to remove the android app) and recreate it on Firbase 5. Verify that the Android client ID is correctly configured in the Firebase console. 1. Click on the `Android` app ![Google Cloud Console Android App Select](/social-login-assets/firebase_gc_android_app_select.webp) 2. Confirm that the SHA1 hash is correctly configured and that it matches the one you copied in the previous steps. ![Google Cloud Console Android App SHA1 Configured](/social-login-assets/firebase_gc_android_app_sha1_configured.webp) 6. Verify that the Web client ID is correctly configured in the Firebase console. 1. Click on the `Web` app ![Google Cloud Console Web App Select](/social-login-assets/firebase_gc_web_app_select.webp) 2. Confirm that the client ID matches the one you copied in the previous steps. ![Google Cloud Console Web App Client ID Configured](/social-login-assets/firebase_gc_web_app_client_id_configured.webp) Note Please ignore the rest of the settings of the web client. We will discuss this on the [web setup guide](/docs/plugins/social-login/firebase/google/web/). Voila! You are now ready to use Google Sign-In with Firebase Authentication on Android. ## Troubleshooting [Section titled “Troubleshooting”](#troubleshooting) If authentication hangs or fails: * Verify the `idToken` audience matches your Firebase web client ID * Check that Google Sign-In is enabled in Firebase Console * Ensure the SHA-1 fingerprint is correctly configured * Review the [example app code](https://github.com/Cap-go/capacitor-social-login/tree/main/example-app/src/authUtils.ts) for reference # Firebase Google Login - General Setup > Learn how to set up Google Sign-In with Firebase Authentication using the Capacitor Social Login plugin. ## Introduction [Section titled “Introduction”](#introduction) This guide will walk you through integrating Google Sign-In with Firebase Authentication using the Capacitor Social Login plugin. This setup allows you to use native Google Sign-In on mobile platforms while leveraging Firebase Auth for backend authentication. ## Setup Steps [Section titled “Setup Steps”](#setup-steps) 1. Please go to [console.cloud.google.com](https://console.cloud.google.com/) 2. Select the project you want to use ![Firebase Project Selector](/social-login-assets/firebase_project_select.webp) 3. Go to the `Authentication` menu 1. Click on `build` 2. Click on `Authentication` ![Firebase Authentication Menu](/social-login-assets/firebase_select_authentication.webp) 4. Click on the `Get started` button ![Firebase Get Started Button](/social-login-assets/firebase_auth_start.webp) 5. Select EITHER `Email/Password` AND `Google` OR `Google` ONLY Note I will select `Email/Password` AND `Google`, as I want to use both, but you could select only `Google`. This is something you can change later. ![Firebase Select Email/Password and Google Button](/social-login-assets/firebase_google_email_auth.webp) ![Firebase enable email authentication](/social-login-assets/firebase_auth_enable_email.webp) ![Firebase save enable google authentication](/social-login-assets/firebase_auth_enable_email_save.webp) ![Firebase enable add provider button](/social-login-assets/firebase_auth_add_provider_after_email.webp) ![Firebase add Google provider after having added email provider](/social-login-assets/firebase_auth_add_google_provider_after_email.webp) 6. Enable the `Google` provider ![Firebase enable google authentication](/social-login-assets/firebase_auth_add_google_provider_enable.webp) 7. Add the support email ![Firebase add support email](/social-login-assets/firebase_auth_add_support_email_google_auth.webp) ![Firebase add support email part 2](/social-login-assets/firebase_auth_add_support_email_google_auth_2.webp) 8. Change the `Public-facing name for project`. Note This will be displayed to the users, so I recommend changing it to something more descriptive. ![Firebase change public facing name](/social-login-assets/firebase_auth_change_public_facing_name.webp) 9. Click on the `Save` button ![Firebase save public facing name](/social-login-assets/firebase_auth_save_google_auth.webp) Voilà, you have now enabled Google Sign-In with Firebase Authentication 🎉 # Firebase Google Login on iOS > Learn how to set up Google Sign-In with Firebase Authentication on iOS using the Capacitor Social Login plugin. ## Introduction [Section titled “Introduction”](#introduction) This guide will help you integrate Google Sign-In with Firebase Authentication on iOS. I assume you have already completed the [general Firebase Google setup](/docs/plugins/social-login/firebase/google/general/). Note I will assume that you have not yet created your iOS app in the Firebase Console. If you have, your steps will be slightly different. ## Setup Steps [Section titled “Setup Steps”](#setup-steps) 1. Go to your project overview over at [console.cloud.google.com](https://console.cloud.google.com/) ![Firebase Project Overview](/social-login-assets/firebase_project_overview.webp) 2. Click on the `Add app` button ![Firebase Add App Button](/social-login-assets/firebase_project_add_app.webp) Note It is possible that you will have to look here for this button. This applies only if you have already created a different app in the Firebase Console. ![Firebase Add App Button](/social-login-assets/firebase_project_add_app_2.webp) 3. Select `iOS` ![Firebase Add App iOS Button](/social-login-assets/firebase_project_add_app_ios.webp) 4. Fill the first part of the form 1. Fill the `Apple bundle ID` 1. Open Xcode at your app using `npx cap open ios` 2. Double click on `App` ![App target in Xcode project navigator](/social-login-assets/xcode_app_click.png) 3. Ensure that you are on `Targets -> App` ![Targets section in Xcode with App selected](/social-login-assets/xcode_targets_app.png) 4. Find your `Bundle Identifier` ![Bundle Identifier field in Xcode project settings](/social-login-assets/xcode_bundle_id.png) Note The ID shown here will differ from the one I will use for the rest of the guide. I will use `app.capgo.plugin.SocialLogin` for the rest of the guide. 5. Copy the `Bundle Identifier` and paste it in the Firebase console ![Firebase Add App iOS Bundle ID Field](/social-login-assets/firebase_project_add_app_ios_bundle_id.webp) 2. Click on the `Register app` button ![Firebase Add App iOS Register Button](/social-login-assets/firebase_project_add_app_ios_register.webp) 5. Skip the `Download config file` step ![Firebase Add App iOS Skip Download Button](/social-login-assets/firebase_project_add_app_ios_skip_download.webp) 6. Skip the `Add firebase SDK` step ![Firebase Add App iOS Skip Download Firebase SDK Button](/social-login-assets/firebase_project_add_app_ios_skip_download_firebase_sdk_2.webp) 7. Skip the `Add initialization code` step ![Firebase Add App iOS Skip Add Initialization Code Button](/social-login-assets/firebase_project_add_app_ios_skip_download_firebase_sdk.webp) 8. Click on the `Continue to console` button ![Firebase Add App iOS Continue to Console Button](/social-login-assets/firebase_project_add_app_ios_continue_to_console.webp) 9. Get your iOS client ID and your `YOUR_DOT_REVERSED_IOS_CLIENT_ID` 1. Go to Google Cloud Console at [console.cloud.google.com](https://console.cloud.google.com/) 2. Find your project 1. Click on the project selector ![Google Cloud Console Project Selector](/social-login-assets/firebase_double_check_gc_project_select.webp) 2. Search up your project by the exact name of your Firebase project and click on it. In my case, it is `sociallogin-tutorial-app`. ![Firebase Project Selector Project](/social-login-assets/firebase_gc_project_select_project.webp) 3. Open the search bar and open `credentials` 1. Open the search bar ![Google Cloud Console Search Bar](/social-login-assets/firebase_double_check_gc_search_bar.webp) 2. Search for `credentials` and click on the `APIs and Services` one (number 2 on the screenshot) ![Google Cloud Console Credentials Search](/social-login-assets/firebase_gc_credentials_search.webp) 4. Click on the `iOS client for [YOUR_APP_ID] (auto created by Google Service)` one. In my case, it is `sociallogin-tutorial-app`. ![Google Cloud Console Credentials iOS Client ID](/social-login-assets/firebase_gc_credentials_ios_client_id.webp) 5. Copy the `Client ID` as well as the `iOS URL scheme`. This will be respectively your `iOSClientId` and `YOUR_DOT_REVERSED_IOS_CLIENT_ID`. Note You will pass the `iOSClientId` in the `initialize` method of the plugin, while you will use the `YOUR_DOT_REVERSED_IOS_CLIENT_ID` in the `Info.plist` file of your app, as explained in the next part of this guide. ![Google Cloud Console Credentials iOS Client ID Copy](/social-login-assets/firebase_gc_credentials_ios_client_id_copy.webp) 10. Get your web client ID 1. Go back to the Firebase console and go to `Build` -> `Authentication` ![Firebase Authentication Menu](/social-login-assets/firebase_select_authentication.webp) 2. Click on the `Sign-in method` button ![Firebase Authentication Sign-in Method Button](/social-login-assets/firebase_select_authentication_sign_in_method.webp) 3. Click on the `Google` provider ![Firebase Authentication Sign-in Method Google Provider](/social-login-assets/firebase_select_authentication_sign_in_method_google.webp) 4. Click on the `Web SDK configuration` button ![Firebase Authentication Sign-in Method Web SDK Configuration Button](/social-login-assets/firebase_select_authentication_sign_in_method_web_sdk_configuration.webp) 5. Copy the `Web client ID`. This will be your `webClientId` in the `initialize` method of the plugin. ![Firebase Authentication Sign-in Method Web SDK Configuration Web Client ID](/social-login-assets/firebase_select_authentication_sign_in_method_web_sdk_configuration_web_client_id.webp) 11. Modify your app’s Info.plist 1. Open Xcode and find the `Info.plist` file ![Info.plist file in Xcode project navigator](/social-login-assets/xcode_info_file.png) 2. Right click this file and open it as source code ![Right-click menu showing Open As Source Code option](/social-login-assets/xcode_open_as_src_code.png) 3. At the bottom of your `Plist` file, you will see a `</dict>` tag ![Closing dict tag in Info.plist file](/social-login-assets/xcode_dict_tag.png) 4. Insert the following fragment just before the closing `</dict>` tag ![Info.plist with URL schemes code inserted before closing dict tag](/social-login-assets/xcode_plist_inserted.png) ```xml <key>CFBundleURLTypes</key> <array> <dict> <key>CFBundleURLSchemes</key> <array> <string>YOUR_DOT_REVERSED_IOS_CLIENT_ID</string> </array> </dict> </array> <key>GIDClientID</key> <string>YOUR_IOS_CLIENT_ID.apps.googleusercontent.com</string> ``` 5. Change the `YOUR_DOT_REVERSED_IOS_CLIENT_ID` to the value copied in step 9 (the iOS URL scheme) ![Info.plist with actual reversed client ID inserted in URL schemes](/social-login-assets/xcode_plist_final.png) Caution Ensure that this value **STARTS** with `com.googleusercontent.apps` 12. Change the `YOUR_IOS_CLIENT_ID` to the iOS Client ID you copied in step 9 13. Save the file with `Command + S` 14. Modify the `AppDelegate.swift` 1. Open the AppDelegate ![AppDelegate.swift file in Xcode project navigator](/social-login-assets/xcode_app_deleg.png) 2. Insert `import GoogleSignIn` at the top of the file ![AppDelegate.swift with GoogleSignIn import added](/social-login-assets/xcode_app_deleg_google_sign_in.png) 3. Find the `func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:])` function ![Original application openURL function in AppDelegate](/social-login-assets/xcode_app_deleg_app_fn.png) 4. Modify the function to look like this ```swift func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool { // Called when the app was launched with a url. Feel free to add additional processing here, // but if you want the App API to support tracking app url opens, make sure to keep this call var handled: Bool handled = GIDSignIn.sharedInstance.handle(url) if handled { return true } return ApplicationDelegateProxy.shared.application(app, open: url, options: options) } ``` ![Modified application openURL function with GoogleSignIn handling](/social-login-assets/xcode_app_deleg_app_fn_mod.png) 5. Save the file with `Command + S` 15. Using the Google login in your app At this step, you are ready to use the Google login in your app. Please use the [authUtils.ts](https://github.com/Cap-go/capacitor-social-login/blob/main/example-app/src/authUtils.ts) file of the example app to authenticate with Google. The user will be automatically created in Firebase Auth on first sign-in ## Troubleshooting [Section titled “Troubleshooting”](#troubleshooting) If authentication hangs or fails: * Verify the `idToken` audience matches your Firebase web client ID * Check that Google Sign-In is enabled in Firebase Console * Ensure Info.plist has the correct URL schemes and GIDClientID * Verify `iOSServerClientId` matches your web client ID * Review the [example app code](https://github.com/Cap-go/capacitor-social-login/tree/main/example-app/src/authUtils.ts) for reference # Firebase Google Login on Web > Learn how to set up Google Sign-In with Firebase Authentication on Web using Firebase's built-in Google Sign-In. ## Introduction [Section titled “Introduction”](#introduction) The Capacitor Social Login plugin **does not support web platforms**. For web applications, you should use Firebase’s built-in Google Sign-In directly, which provides a more reliable popup-based authentication flow. ## Why Not Use the Plugin on Web? [Section titled “Why Not Use the Plugin on Web?”](#why-not-use-the-plugin-on-web) The Capacitor Social Login plugin is designed for native mobile platforms (Android and iOS) where it can leverage platform-specific authentication flows. For web, Firebase’s native `signInWithPopup` method is: * ✅ More reliable and better supported * ✅ Handles browser session storage automatically * ✅ Provides better error handling * ✅ No additional configuration needed ## Setup Steps [Section titled “Setup Steps”](#setup-steps) 1. **Configure Firebase Project** Ensure your Firebase project has Google Sign-In enabled: * Go to [Firebase Console](https://console.firebase.google.com/) * Navigate to Authentication > Sign-in method * Enable Google Sign-In provider 2. Add your authorized domains 1. Go to your project overview over at [console.cloud.google.com](https://console.cloud.google.com/) ![Firebase Project Overview](/social-login-assets/firebase_project_overview.webp) 2. Open the `Authentication` menu ![Firebase Authentication Menu](/social-login-assets/firebase_select_authentication.webp) 3. Click on the `Settings` button ![Firebase Authentication Sign-in Method Button](/social-login-assets/firebase_select_authentication_settings.webp) 4. Setup the `Authorized domains` ![Firebase Authentication Settings Authorized Domains](/social-login-assets/firebase_select_authentication_settings_authorized_domains.webp) ## Example Implementation [Section titled “Example Implementation”](#example-implementation) See the [authUtils.ts](https://github.com/Cap-go/capacitor-social-login/blob/main/example-app/src/authUtils.ts) file in the example app for a complete implementation that: * Uses Firebase’s `signInWithPopup` for web platforms * Uses Capacitor Social Login plugin for Android/iOS platforms * Handles platform detection automatically The example shows how to conditionally use Firebase’s built-in method for web while using the plugin for native platforms. ## Additional Resources [Section titled “Additional Resources”](#additional-resources) * [Firebase Authentication Documentation](https://firebase.google.com/docs/auth) - Complete Firebase Auth documentation * [Firebase Google Sign-In for Web](https://firebase.google.com/docs/auth/web/google-signin) - Official Firebase guide for Google Sign-In on web * [Google Login Setup Guide](/docs/plugins/social-login/google/general/) - Guide for configuring authorized domains and OAuth consent screen # Firebase Integration Introduction > Learn how to integrate Firebase Authentication with the Capacitor Social Login plugin for a complete authentication solution. ## Overview [Section titled “Overview”](#overview) This tutorial will guide you through setting up Firebase Authentication with the Capacitor Social Login plugin. This integration allows you to use native social login providers (Google, Apple, Facebook, Twitter) on mobile platforms while leveraging Firebase Auth for backend authentication and Firestore for data storage. ## What You’ll Learn [Section titled “What You’ll Learn”](#what-youll-learn) * How to configure Firebase Authentication * How to integrate Capacitor Social Login plugin with Firebase Auth * Platform-specific setup for Android, iOS, and Web ## What You’ll Need [Section titled “What You’ll Need”](#what-youll-need) Before you begin, make sure you have: 1. **A Firebase Project** * Create a project at [Firebase Console](https://console.firebase.google.com/) * Enable Authentication (Email/Password and Google Sign-In) * Get your Firebase configuration credentials 2. **Firebase JS SDK** * Install Firebase in your project: ```bash npm install firebase ``` 3. **A Capacitor Project** * An existing Capacitor application * Capacitor Social Login plugin installed: ```bash npm install @capgo/capacitor-social-login npx cap sync ``` ## Example Application [Section titled “Example Application”](#example-application) A complete working example is available in the repository: **Code Repository**: [You can find the code repository here](https://github.com/Cap-go/capacitor-social-login/tree/main/example-app) The example app demonstrates: * Email/password authentication with Firebase * Google Sign-In integration (Android, iOS, and Web) * A simple key-value store using Firebase Firestore collections * User-specific data storage in Firestore subcollections ## A word about using the Firebase SDK on Capacitor [Section titled “A word about using the Firebase SDK on Capacitor”](#a-word-about-using-the-firebase-sdk-on-capacitor) When using the Firebase JS SDK on Capacitor, you need to be aware that when using the authentication methods, you need to initialize the Firebase Auth instance a bit differently. On the web platform, you would use the `getAuth` function to get the Firebase Auth instance. ```typescript import { initializeApp } from 'firebase/app'; import { getAuth } from 'firebase/auth'; const app = initializeApp(firebaseConfig); const auth = getAuth(app); ``` Unfortunately, on Capacitor, this does not work and causes Firebase auth to hang. As stated in [this blog post](https://harryherskowitz.com/2021/08/23/firebase-capacitor.html), you need to use the `initializeAuth` function to initialize the Firebase Auth instance. This looks like this: ```typescript import { initializeApp } from 'firebase/app'; import { initializeAuth } from 'firebase/auth'; const app = initializeApp(firebaseConfig); function whichAuth() { let auth; if (Capacitor.isNativePlatform()) { auth = initializeAuth(app, { persistence: indexedDBLocalPersistence, }); } else { auth = getAuth(app); } return auth; } export const auth = whichAuth(); ``` ## Next Steps [Section titled “Next Steps”](#next-steps) Continue with the setup guides: * [Firebase Setup](../google/general/) - Configure Firebase project * [Android Setup](../google/android/) - Android-specific configuration * [iOS Setup](../google/ios/) - iOS-specific configuration * [Web Setup](../google/web/) - Web-specific configuration # Getting Started > Discover how to install and configure the Capacitor Social Login plugin to enhance your app's authentication with seamless integration for Google, Apple, Facebook, and generic OAuth2 logins. 1. **Install the package** ```sh bun add @capgo/capacitor-social-login ``` 2. **Sync with native projects** ```sh bunx cap sync ``` 3. **Initialize in app startup** ```typescript import { SocialLogin } from '@capgo/capacitor-social-login'; await SocialLogin.initialize({ google: { webClientId: 'your-google-web-client-id', iOSServerClientId: 'your-google-server-client-id', mode: 'online', }, apple: { clientId: 'your-apple-service-id', useProperTokenExchange: true, useBroadcastChannel: true, }, facebook: { appId: 'your-facebook-app-id', }, twitter: { clientId: 'your-twitter-client-id', redirectUrl: 'myapp://oauth/twitter', }, oauth2: { github: { appId: 'your-github-client-id', authorizationBaseUrl: 'https://github.com/login/oauth/authorize', accessTokenEndpoint: 'https://github.com/login/oauth/access_token', redirectUrl: 'myapp://oauth/github', scope: 'read:user user:email', pkceEnabled: true, }, }, }); ``` ## Core flow examples [Section titled “Core flow examples”](#core-flow-examples) ### Login [Section titled “Login”](#login) ```typescript await SocialLogin.login({ provider: 'google', options: { scopes: ['profile', 'email'] }, }); await SocialLogin.login({ provider: 'oauth2', options: { providerId: 'github', scope: 'read:user user:email', }, }); ``` ### Session checks [Section titled “Session checks”](#session-checks) ```typescript const status = await SocialLogin.isLoggedIn({ provider: 'google' }); await SocialLogin.logout({ provider: 'google' }); ``` ### Auth codes and refresh [Section titled “Auth codes and refresh”](#auth-codes-and-refresh) ```typescript // For providers that support this mode const authCodeResult = await SocialLogin.getAuthorizationCode({ provider: 'google' }); await SocialLogin.refresh({ provider: 'google', options: {} as never }); ``` ### Advanced helpers [Section titled “Advanced helpers”](#advanced-helpers) ```typescript const jwt = await SocialLogin.decodeIdToken({ idToken: 'eyJhbGciOi...', }); const { date } = await SocialLogin.getAccessTokenExpirationDate({ accessTokenExpirationDate: Date.now() + 3600 * 1000, }); const expired = await SocialLogin.isAccessTokenExpired({ accessTokenExpirationDate: Date.now() + 1000, }); const active = await SocialLogin.isRefreshTokenAvailable({ refreshToken: 'a-token' }); ``` ## Provider-specific notes [Section titled “Provider-specific notes”](#provider-specific-notes) ### Google offline mode [Section titled “Google offline mode”](#google-offline-mode) `google.mode: 'offline'` returns `serverAuthCode` from login. In this mode logout, isLoggedIn, getAuthorizationCode, and refresh are not available. Use `serverAuthCode` only as input to your backend token exchange. If you need to call `SocialLogin.refresh()` in the app, use `google.mode: 'online'` instead. ### Apple [Section titled “Apple”](#apple) Set `useProperTokenExchange: true` for strict token handling and `useBroadcastChannel: true` for Android simplified setup. ### OAuth2 web redirect flow [Section titled “OAuth2 web redirect flow”](#oauth2-web-redirect-flow) Use `OAuth2LoginOptions.flow: 'redirect'` for web flows that navigate away from the page. ## Provider configuration in Capacitor [Section titled “Provider configuration in Capacitor”](#provider-configuration-in-capacitor) You can disable unused providers to reduce native binaries: ```typescript import type { CapacitorConfig } from '@capacitor/cli'; const config: CapacitorConfig = { appId: 'com.example.app', appName: 'My App', webDir: 'dist', plugins: { SocialLogin: { providers: { google: true, facebook: true, apple: true, twitter: false, }, }, }, }; ``` ## Related documentation [Section titled “Related documentation”](#related-documentation) * [Integrations overview](/docs/plugins/social-login/integrations/) * [Better Auth integration](/docs/plugins/social-login/better-auth/) * [OAuth2 and OIDC providers](/docs/plugins/social-login/oauth2/) * [Migrate from Ionic Auth Connect](/docs/upgrade/from-ionic-auth-connect/) * [Social Login Auth Connect migration guide](/docs/plugins/social-login/migrations/ionic-auth-connect/) * [Migrate legacy providers](/docs/plugins/social-login/migrations/google/) * [Ionic enterprise plugins migration solution](/solutions/ionic-enterprise-plugins/) # Google Login on Android > This guide provides a comprehensive walkthrough on setting up Google Login using Capacitor for Android devices, detailing each step to ensure a smooth integration process and addressing potential challenges you may encounter. ## Introduction [Section titled “Introduction”](#introduction) In this guide, you will learn how to setup Google Login with Capgo Social Login for Android. I assume that you have already read the [general setup guide](/docs/plugins/social-login/google/general/). ## Using Google login on Android [Section titled “Using Google login on Android”](#using-google-login-on-android) In this part, you will learn how to setup Google login in Android. Caution The Android SHA1 certificate is beyond painful and I wouldn’t wish it on anyone to have to set this up. The following steps assume the simplest scenario of an app that isn’t published to Google Play Store and that is only used by the local simulator, or development hardware device. If you have deployed your app to Google Play Store, you **MUST** add an additional Android client ID that contains the SHA1 from Google Play console for production releases. You can find the SHA1 hash that Google Play uses to sign your release bundle under `Test and release > Setup > App Signing`. Finally, it’s important to mention that if you mess up, the error will NOT be obvious. It may be very difficult to debug. If you struggle with the setup, please look at the [Github issues](https://github.com/Cap-go/capacitor-social-login/issues). Additionally, you may look at the troubleshooting section of the [Google Login setup for Android](#troubleshooting) for more information. Note You may create multiple Android client IDs. This is required if you have multiple SHA1 certificates. 1. Create an Android client ID. 1. Click on the search bar ![Google Console search bar](/social-login-assets/google_cons_search.png) 2. Search for `credentials` and click on the `APIs and Services` one (number 2 on the screenshot) ![Search results showing credentials option with APIs and Services highlighted](/social-login-assets/google_cons_cred_search.png) 3. Click on the `create credentials` ![Create credentials button in Google Console](/social-login-assets/google_cons_create_cred.png) 4. Select `OAuth client ID` ![OAuth client ID option in credentials creation menu](/social-login-assets/google_cons_cred_oauth.png) 5. Select the `Android` application type ![Application type selection with Android option highlighted](/social-login-assets/google_cons_app_type_android.png) 6. Open Android Studio 7. At the very bottom of the navigator, find the `Gradle Scripts` ![Gradle Scripts section in Android Studio project navigator](/social-login-assets/studio_gradle_scripts.png) 8. Find `build.gradle` for the module `app` ![build.gradle (Module: app) file in Gradle Scripts section](/social-login-assets/studio_build_gradle.png) 9. Copy the `android.defaultConfig.applicationId`. This will be your `package name` in the Google console ![Build.gradle file showing applicationId configuration](/social-login-assets/studio_build_gradle_app_id.png) 10. Now, open the terminal. Make sure that you are in the `android` folder of your app and run `./gradlew signInReport` ![Terminal showing gradlew signInReport command](/social-login-assets/term_sign_report.png) 11. Scroll to the top of this command. You should see the following. Copy the `SHA1`. ![Terminal output showing SHA1 certificate fingerprint](/social-login-assets/term_sign_report_res.png) 12. Now, go back to the Google Console. Enter your `applicationId` as the `Package Name` and your SHA1 in the certificate field and click `create` ![Android client creation form with package name and SHA1 fields filled in](/social-login-assets/google_cons_creat_android_client.png) 2. Create a web client (this is required for Android) 1. Go to the `Create credentials` page in Google Console 2. Set application type to `Web` ![Application type selection with Web option highlighted](/social-login-assets/google_cons_app_type_web.png) 3. Click `Create` ![Web client creation form with Create button at bottom](/social-login-assets/google_cons_web_app_create.png) 4. Copy the client ID, you’ll use this as the `webClientId` in your JS/TS code ![Client ID details showing Web client ID to copy](/social-login-assets/google_cons_copy_web_client_id.png) 3. Modify your `MainActivity` 1. Please open your app in Android Studio. You can run `cap open android` 2. Find `MainActivity.java` 1. Open the `app` folder ![App folder in Android Studio project navigator](/social-login-assets/studio_app_folder.png) 2. Find `java` ![Java folder in Android Studio project structure](/social-login-assets/studio_app_java.png) 3. Find your `MainActivity.java` and click on it ![MainActivity.java file in package structure](/social-login-assets/studio_app_java_activity_main.png) 3. Modify `MainActivity.java`. Please add the following code ```java import ee.forgr.capacitor.social.login.GoogleProvider; import ee.forgr.capacitor.social.login.SocialLoginPlugin; import ee.forgr.capacitor.social.login.ModifiedMainActivityForSocialLoginPlugin; import com.getcapacitor.PluginHandle; import com.getcapacitor.Plugin; import android.content.Intent; import android.util.Log; import com.getcapacitor.BridgeActivity; // ModifiedMainActivityForSocialLoginPlugin is VERY VERY important !!!!!! public class MainActivity extends BridgeActivity implements ModifiedMainActivityForSocialLoginPlugin { @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode >= GoogleProvider.REQUEST_AUTHORIZE_GOOGLE_MIN && requestCode < GoogleProvider.REQUEST_AUTHORIZE_GOOGLE_MAX) { PluginHandle pluginHandle = getBridge().getPlugin("SocialLogin"); if (pluginHandle == null) { Log.i("Google Activity Result", "SocialLogin login handle is null"); return; } Plugin plugin = pluginHandle.getInstance(); if (!(plugin instanceof SocialLoginPlugin)) { Log.i("Google Activity Result", "SocialLogin plugin instance is not SocialLoginPlugin"); return; } ((SocialLoginPlugin) plugin).handleGoogleLoginIntent(requestCode, data); } } // This function will never be called, leave it empty @Override public void IHaveModifiedTheMainActivityForTheUseWithSocialLoginPlugin() {} } ``` 4. Save the file 4. Use Google Login in your application 1. First, import `SocialLogin` ```typescript import { SocialLogin } from '@capgo/capacitor-social-login'; ``` 2. Call initialize. This should be called only once. ```typescript // onMounted is Vue specific // webClientId is the client ID you got in the web client creation step not the android client ID. onMounted(() => { SocialLogin.initialize({ google: { webClientId: '673324426943-avl4v9ubdas7a0u7igf7in03pdj1dkmg.apps.googleusercontent.com', } }) }) ``` 3. Call `SocialLogin.login`. Create a button and run the following code on click. ```typescript const res = await SocialLogin.login({ provider: 'google', options: {} }) // handle the response console.log(JSON.stringify(res)) ``` Caution If you initialize Google with `mode: 'offline'`, `SocialLogin.login()` returns `serverAuthCode` for your backend exchange flow. Do not call `SocialLogin.refresh({ provider: 'google' })` in the app in that mode. Exchange `serverAuthCode` on your backend, store the Google refresh token there, and refresh on the backend. 5. Configure the emulator for testing 1. Go into `Device manager` and click the plus button ![Device Manager in Android Studio with plus button highlighted](/social-login-assets/studio_device_man.png) 2. Create a virtual device ![Create Virtual Device button in Virtual Device Configuration](/social-login-assets/studio_create_virt_dev.png) 3. Select any device with a `Play Store` icon ![Hardware selection showing devices with Play Store support](/social-login-assets/studio_new_dev_select_hardware.png) As you can see, the `pixel 8` supports the `Play Store` services 4. Click `next` ![Next button in device creation wizard](/social-login-assets/studio_new_dev_next_1.png) 5. Make sure that the OS image is of type `Google Play`. **IT MUST** be of type `Google Play` ![System image selection showing Google Play type images](/social-login-assets/studio_new_dev_google_play_dev_type.png) 6. Click next ![Next button in system image selection screen](/social-login-assets/studio_new_dev_next_1.png) 7. Confirm your device. You can name your emulator as you prefer ![Device configuration verification screen with Finish button](/social-login-assets/studio_new_dev_next_3.png) 8. Go into `Device Manager` and boot up your simulator ![Device Manager with virtual device listed and play button](/social-login-assets/studio_dev_manager.png) 9. After the simulator boots up, go into its settings ![Android emulator showing settings app](/social-login-assets/emul_and_settings_1.png) 10. Go into `Google Play` ![Settings screen with Google Play option](/social-login-assets/emul_and_settings_2.png) 11. Click `Update` and wait about 60 seconds ![Google Play update screen with Update button](/social-login-assets/emul_and_settings_update_play_store.png) 6. Test your application If you did everything correctly, you should see the Google login flow working properly: ![Demo of Google login flow on Android showing sign-in process and successful authentication](/social-login-assets/google_android_final_login_show.webp) ## Troubleshooting [Section titled “Troubleshooting”](#troubleshooting) If you have any issues, please look at the [Github issues](https://github.com/Cap-go/capacitor-social-login/issues). The issues with Google login are **ALWAYS** related to the SHA1 certificate. If you cannot get the development SHA1 certificate, try to use a custom keystore. [Here](https://github.com/Cap-go/capacitor-social-login/issues/147#issuecomment-2849742574) is a comment explaining how to add keystore to your project. # Google Login Setup > This guide provides a comprehensive overview on setting up Google Login using Capacitor, detailing each step to ensure a seamless integration process and addressing potential challenges you may encounter. ## Introduction [Section titled “Introduction”](#introduction) In this guide, you will learn how to setup Google Login with Capgo Social Login. You will need the following in order to setup Google Login: * A Google account ## General setup [Section titled “General setup”](#general-setup) Note This step is required regardless of which the platform you decide to use. In this part, you will setup the login screen displayed by Google. 1. Please go to [console.cloud.google.com](https://console.cloud.google.com/) 2. Click on the project selector ![Google Console Project Selector](/social-login-assets/google_cons_project_selector.png) 3. If you don’t have a project already, please **create a new project**. 1. Click on `New project` ![New Project button in Google Console](/social-login-assets/google_cons_new_project_btn.png) 2. Name your project and click `Create` ![Project naming screen showing name field and Create button](/social-login-assets/google_cons_name_projec.png) 3. Ensure that you are on the right project ![Project name showing in the selector indicating correct project selection](/social-login-assets/google_cons_right_proj.png) 4. Start to configure the `OAuth consent screen` 1. Click on the search bar ![Google Console search bar](/social-login-assets/google_cons_search.png) 2. Search for `OAuth consent screen` and click on it ![Search results showing OAuth consent screen option](/social-login-assets/google_cons_search_2.png) 3. Configure the consent screen Note I will assume that you are developing an app open to the public, so I will use the `external` user type. Please select the user type that suits you the best AND click `create` Click on `create` ![OAuth consent screen user type selection with External and Internal options](/social-login-assets/google_cons_oauth_const_scr.png) 5. Fill the information about your app 1. Let’s start with the `App Information` ![App Information section showing App name and User support email fields](/social-login-assets/google_cons_app_inf.png) * Please type in your `App Name` Caution **THIS WILL BE DISPLAYED TO THE USERS** * Enter the `user support email` Note You can learn more about the support email [here](https://support.google.com/cloud/answer/10311615#user-support-email\&zippy=%2Cuser-support-email/) 2. You **CAN** add the app logo. ![App logo upload section in OAuth consent screen](/social-login-assets/google_cons_app_logo.png) Note This is not obligatory and I will skip this step 3. You **SHOULD** configure the `App domain` ![App domain configuration section with authorized domains field](/social-login-assets/google_cons_app_doma.png) Note I will not do that because this is just a simple demonstration that will **NOT** get published, but I strongly recommend filling this section. 4. You **HAVE TO** provide the developer’s email ![Developer contact information section with email field](/social-login-assets/google_cons_dev_cont_inf.png) 5. Click on `save and continue` ![Save and Continue button at bottom of form](/social-login-assets/google_cons_cons_sav_cont.png) 6. Configure the scopes 1. Click on `add or remove scopes` ![Add or remove scopes button in scopes configuration screen](/social-login-assets/google_cons_add_rm_sco.png) 2. Select the following scopes and click `update` ![Scope selection dialog with email and profile scopes selected](/social-login-assets/google_cons_update_scope.png) 3. Click `save and continue` ![Save and Continue button in scopes screen](/social-login-assets/google_cons_scope_save.png) 7. Add a test user 1. Click on `add users` ![Add users button in test users section](/social-login-assets/google_cons_add_test_usr.png) 2. Enter your Google email, click enter, and click `add` ![Email input field and Add button for test users](/social-login-assets/google_cons_add_test_usr_2.png) 3. Click `save and continue` ![Save and Continue button in test users screen](/social-login-assets/google_cons_test_usr_save.png) 8. Click `back to dashboard` ![Back to dashboard button at bottom of completion page](/social-login-assets/google_cons_back_to_dahs.png) 9. Submit your app for verification Note I strongly recommend submitting you app for verification. This is outside the scope of this tutorial. You can learn more [here](https://support.google.com/cloud/answer/13463073/). This isn’t required for local testing, but is required for production. ## Differences between online access and offline access [Section titled “Differences between online access and offline access”](#differences-between-online-access-and-offline-access) There are multiple ways to use Google Login with Capacitor. Here is a table that summarizes the differences between the two: | | Online access | Offline access | | :---------------------: | :-----------: | :------------: | | Requires a backend | ❌ | ✅ | | Long-lived access token | ❌ | ✅ | | Easy setup | ✅ | ❌ | Note **Offline mode** means that your backend can access Google’s APIs even when the user is not actively using your app (i.e., when the user is “offline” from your app’s perspective). Long-lived access tokens enable this functionality by allowing the backend to call Google APIs on behalf of the user at any time. Caution **Offline mode REQUIRES a backend server.** When using offline mode, the frontend receives minimal information (primarily just a server auth code). Without a backend to exchange this code for tokens and user information, offline mode provides no useful data to your frontend application. Caution `SocialLogin.refresh({ provider: 'google' })` does **not** work with `google.mode: 'offline'`. In offline mode the plugin only gives you `serverAuthCode`, and your backend must exchange that code for access and refresh tokens, then refresh those tokens on the backend. If you still do not know which one you should choose, please consider the following scenarios: 1. You want the user to login, immediately after you are going to issue him a custom JWT. Your app will NOT call Google APIs In this case, choose online access. 2. Your app will call some Google APIs from the client, but never from the backend In this case, choose online access 3. Your app will call some google APIs from the backend, but only when the user is actively using the app In this case, choose online access 4. Your app will periodically check the user’s calendar, even when he is not actively using the app In this case, choose offline access ## An example backend for online access [Section titled “An example backend for online access”](#an-example-backend-for-online-access) In this part of the tutorial, I will show how to validate the user on your backend. This example will be very simple and it will be based on the following technologies: * [Typescript](https://www.typescriptlang.org/) * [Hono](https://hono.dev/) * [Javascript’s fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Window/fetch) You can find the code for this example [here](https://github.com/WcaleNieWolny/capgo-social-login-backend-demo/blob/141c01d93a85240e31a0d488a89df13c842708b1/index.ts#L135-L153) As you can see: ![VS Code showing Google authentication code that verifies tokens](/social-login-assets/vscode_auth_google.png) The idea is rather simple. You send a simple `GET` request to `https://www.googleapis.com/oauth2/v3/tokeninfo` and this returns you whether the token is valid or not and if it it is, it gives you the email of the user. It also gives you some other info about the user token ![Google OAuth Playground showing token information response with user details](/social-login-assets/google_auth_playground_token_info.png) From there, you could issue the user with your own JWT or issue some sort of session cookie. The possibilities are endless, for the final auth implementation. If you do want to call Google API’s, I would strongly recommend looking at [Google’s OAuth 2.0 Playground](https://developers.google.com/oauthplayground). From there you can easily see what APIs you can call. ## Using offline access with your own backend [Section titled “Using offline access with your own backend”](#using-offline-access-with-your-own-backend) In order to use offline access you will need the following: * An HTTP server In this example, I will be using the following technologies to provide the offline access in my app: * [Hono](https://hono.dev/) * [Hono Zod validator](https://hono.dev/docs/guides/validation#with-zod) * [Zod](https://zod.dev/) * [Hono JWT](https://hono.dev/docs/helpers/jwt#jwt-authentication-helper) * [LowDb](https://www.npmjs.com/package/lowdb) (a simple database) The code for this example can be found [here](https://github.com/WcaleNieWolny/capgo-social-login-backend-demo/blob/aac7a8c909f650a8c2cd7f88c97f5f3c594ce9ba/index.ts#L139-L287) As for the client code, it looks like this: ```typescript import { Capacitor } from '@capacitor/core'; import { GoogleLoginOfflineResponse, SocialLogin } from '@capgo/capacitor-social-login'; import { usePopoutStore } from '@/popoutStore'; // <-- specific to my app const baseURL = "[redacted]"; async function fullLogin() { await SocialLogin.initialize({ google: { webClientId: '[redacted]', iOSClientId: '[redacted]', iOSServerClientId: 'The same value as webClientId', mode: 'offline' // <-- important } }) const response = await SocialLogin.login({ provider: 'google', options: { forceRefreshToken: true // <-- important } }) if (response.provider === 'google') { const result = response.result as GoogleLoginOfflineResponse const res = await fetch(`${baseURL}/auth/google_offline`, { headers: { "Content-Type": "application/json" }, body: JSON.stringify({ serverAuthCode: result.serverAuthCode, platform: Capacitor.getPlatform() }), method: "POST" }) if (res.status !== 200) { popoutStore.popout("Full google login failed", "check console"); return } const { jwt } = await res.json(); const userinfo = await fetch(`${baseURL}/auth/get_google_user`, { headers: { Authorization: `Bearer ${jwt}` } }) if (userinfo.status !== 200) { popoutStore.popout("Full google (userinfo) login failed", "check console"); return } popoutStore.popout("userinfo res", await userinfo.text()); } } ``` Notice what is missing here: there is no `SocialLogin.refresh()` call in the app. That is intentional. In Google offline mode, refresh happens after your backend exchanges `serverAuthCode` and stores the refresh token securely. # Google Login on iOS > This guide offers a comprehensive walkthrough for configuring Google Login with Capacitor on iOS, detailing each step to ensure a smooth integration process. ## Introduction [Section titled “Introduction”](#introduction) In this guide, you will learn how to setup Google Login with Capgo Social Login for iOS. I assume that you have already read the [general setup guide](/docs/plugins/social-login/google/general/). ## Using Google login on iOS [Section titled “Using Google login on iOS”](#using-google-login-on-ios) In this part, you will learn how to setup Google login in iOS. 1. Create an iOS client ID in the Google console 1. Click on the search bar ![Google Console search bar](/social-login-assets/google_cons_search.png) 2. Search for `credentials` and click on the `APIs and Services` one (number 2 on the screenshot) ![Search results showing credentials option with APIs and Services highlighted](/social-login-assets/google_cons_cred_search.png) 3. Click on the `create credentials` ![Create credentials button in Google Console](/social-login-assets/google_cons_create_cred.png) 4. Select `OAuth client ID` ![OAuth client ID option in credentials creation menu](/social-login-assets/google_cons_cred_oauth.png) 5. Select the `Application type` to `iOS` ![Application type selection with iOS option highlighted](/social-login-assets/goolge_cons_cred_type_app_tye.png) 6. Find the bundle ID 1. Open Xcode 2. Double click on `App` ![App target in Xcode project navigator](/social-login-assets/xcode_app_click.png) 3. Ensure that you are on `Targets -> App` ![Targets section in Xcode with App selected](/social-login-assets/xcode_targets_app.png) 4. Find your `Bundle Identifier` ![Bundle Identifier field in Xcode project settings](/social-login-assets/xcode_bundle_id.png) 5. Go back to the Google Console and paste your `Bundle Identifier` into `Bundle ID` ![Bundle ID field in Google Console iOS client creation form](/social-login-assets/google_cons_ios_bd_id.png) 7. Optionally, add your `App Store ID` or `Team ID` into the client ID if you have published your app to App Store 8. After filling all the details, click `create` ![Create button at bottom of iOS client creation form](/social-login-assets/google_cons_ios_cred_creat.png) 9. Click `OK` ![OK button on client ID created confirmation dialog](/social-login-assets/google_cons_ios_click_ok.png) 10. Open the newly created iOS client ![Newly created iOS client in credentials list](/social-login-assets/google_cons_open_new_ios.png) 11. Copy the following data ![Client ID details showing Client ID and reversed client ID to copy](/social-login-assets/google_cons_ios_what_to_copy.png) Note The `nr. 1` in this image will later become the `iOSClientId` in the `initialize` call. The `nr. 2` in this image will later become `YOUR_DOT_REVERSED_IOS_CLIENT_ID` 2. Modify your app’s Info.plist 1. Open Xcode and find the `Info.plist` file ![Info.plist file in Xcode project navigator](/social-login-assets/xcode_info_file.png) 2. Right click this file and open it as source code ![Right-click menu showing Open As Source Code option](/social-login-assets/xcode_open_as_src_code.png) 3. At the bottom of your `Plist` file, you will see a `</dict>` tag ![Closing dict tag in Info.plist file](/social-login-assets/xcode_dict_tag.png) 4. Insert the following fragment just before the closing `</dict>` tag ![Info.plist with URL schemes code inserted before closing dict tag](/social-login-assets/xcode_plist_inserted.png) ```xml <key>CFBundleURLTypes</key> <array> <dict> <key>CFBundleURLSchemes</key> <array> <string>YOUR_DOT_REVERSED_IOS_CLIENT_ID</string> </array> </dict> </array> ``` 5. Change the `YOUR_DOT_REVERSED_IOS_CLIENT_ID` to the value copied in the previous step ![Info.plist with actual reversed client ID inserted in URL schemes](/social-login-assets/xcode_plist_final.png) Caution Ensure that this value **STARTS** with `com.googleusercontent.apps` 6. Save the file with `Command + S` 3. Modify the `AppDelegate.swift` 1. Open the AppDelegate ![AppDelegate.swift file in Xcode project navigator](/social-login-assets/xcode_app_deleg.png) 2. Insert `import GoogleSignIn` at the top of the file ![AppDelegate.swift with GoogleSignIn import added](/social-login-assets/xcode_app_deleg_google_sign_in.png) 3. Find the `func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:])` function ![Original application openURL function in AppDelegate](/social-login-assets/xcode_app_deleg_app_fn.png) 4. Modify the function to look like this ```swift func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool { // Called when the app was launched with a url. Feel free to add additional processing here, // but if you want the App API to support tracking app url opens, make sure to keep this call var handled: Bool handled = GIDSignIn.sharedInstance.handle(url) if handled { return true } return ApplicationDelegateProxy.shared.application(app, open: url, options: options) } ``` ![Modified application openURL function with GoogleSignIn handling](/social-login-assets/xcode_app_deleg_app_fn_mod.png) 5. Save the file with `Command + S` 4. Setup Google login in your JavaScript/TypeScript code 1. Import `SocialLogin` and `Capacitor` ```typescript import { SocialLogin } from '@capgo/capacitor-social-login'; import { Capacitor } from '@capacitor/core'; ``` 2. Call the initialize method (this should be called only once) **Basic setup (online mode - recommended for most apps):** ```typescript // onMounted is Vue specific onMounted(() => { SocialLogin.initialize({ google: { iOSClientId: '673324426943-redacted.apps.googleusercontent.com', mode: 'online' // Default mode } }) }) ``` **Advanced setup with additional client IDs:** ```typescript onMounted(() => { SocialLogin.initialize({ google: { webClientId: 'YOUR_WEB_CLIENT_ID', // Optional: for web platform support iOSClientId: 'YOUR_IOS_CLIENT_ID', // Required: from step 1 iOSServerClientId: 'YOUR_WEB_CLIENT_ID', // Optional: same as webClientId, needed for some advanced features mode: 'online' // 'online' or 'offline' } }) }) ``` Note **Client ID Requirements:** * `iOSClientId`: **Required** - Must end with `googleusercontent.com` (from step 1 above) * `webClientId`: **Optional** - Only needed if you also support web platform or need advanced features * `iOSServerClientId`: **Optional** - Should be the same value as `webClientId` when provided For advanced setup with `webClientId` and `iOSServerClientId`, see the [web setup guide](/docs/plugins/social-login/google/web/) for creating these credentials. Caution **About offline mode:** When using `mode: 'offline'`, the login response will not contain user data directly. Instead, you’ll receive a server auth code that must be exchanged for user information via your backend server. `SocialLogin.refresh({ provider: 'google' })` is not available in this mode; refresh must happen on your backend after exchanging `serverAuthCode`. See the [general setup guide](/docs/plugins/social-login/google/general/#using-offline-access-with-your-own-backend) for implementation details. 3. Implement the login function. Create a button and run the following code on click **For online mode:** ```typescript const res = await SocialLogin.login({ provider: 'google', options: {} }) // handle the response - contains user data console.log(JSON.stringify(res)) ``` **For offline mode:** ```typescript const res = await SocialLogin.login({ provider: 'google', options: { forceRefreshToken: true // Recommended for offline mode } }) // res contains serverAuthCode, not user data // Send serverAuthCode to your backend to get user information // Do not call SocialLogin.refresh() in offline mode console.log('Server auth code:', res.result.serverAuthCode) ``` 5. Test your application 1. Build your app and run `cap sync` 2. If you’ve done everything correctly, you should see the Google login flow working properly ![Demo of Google login flow on iOS showing sign-in process and successful authentication](/social-login-assets/google_final_ios_v2.webp) Note The language in the Google prompt depends on your device’s language settings. ## Known Problems [Section titled “Known Problems”](#known-problems) ### Privacy Screen Plugin Incompatibility [Section titled “Privacy Screen Plugin Incompatibility”](#privacy-screen-plugin-incompatibility) The Google Login plugin is incompatible with [@capacitor/privacy-screen](https://github.com/ionic-team/capacitor-privacy-screen). When using both plugins together, the Google login webview will be interrupted by the privacy screen. **Workaround:** Call `await PrivacyScreen.disable();` before calling the login function: ```typescript import { PrivacyScreen } from '@capacitor/privacy-screen'; import { SocialLogin } from '@capgo/capacitor-social-login'; await PrivacyScreen.disable(); await SocialLogin.login({ provider: 'google', options: {} }); ``` # Google Login on Web > This guide provides a comprehensive walkthrough for setting up Google Login on web applications using Capacitor and the @capgo/capacitor-social-login plugin, ensuring a seamless integration process by covering all necessary steps and configurations. ## Introduction [Section titled “Introduction”](#introduction) In this guide, you will learn how to setup Google Login with Capgo Social Login for web applications. I assume that you have already read the [general setup guide](/docs/plugins/social-login/google/general/). ## Using Google login on the web [Section titled “Using Google login on the web”](#using-google-login-on-the-web) Using the google login on the web is rather simple. In order to use it, you have to do the following: 1. Create a web client in the Google Console Note If you have already configured Google Login for Android, you can skip this step as you’ve already created a web client. You can proceed directly to step 2. 1. Click on the search bar ![Google Console search bar](/social-login-assets/google_cons_search.png) 2. Search for `credentials` and click on the `APIs and Services` option (number 2 on the screenshot) ![Search results showing credentials option with APIs and Services highlighted](/social-login-assets/google_cons_cred_search.png) 3. Click on the `create credentials` ![Create credentials button in Google Console](/social-login-assets/google_cons_create_cred.png) 4. Select `OAuth client ID` ![OAuth client ID option in credentials creation menu](/social-login-assets/google_cons_cred_oauth.png) 5. Select the `Application type` as `Web application` ![Application type selection with Web option highlighted](/social-login-assets/google_cons_app_type_web.png) 6. Name your client and click `Create` ![Web client creation form with name field highlighted](/social-login-assets/google_cons_web_app_create.png) 7. Copy the client ID, you’ll use this as the `webClientId` in your application ![Client ID details showing Web client ID to copy](/social-login-assets/google_cons_copy_web_client_id.png) 2. Configure the web client in the Google Console 1. Please open the [credentials page](https://console.cloud.google.com/apis/credentials) and click on your web client ![Credentials list showing web client to click](/social-login-assets/google_cons_open_web_client_id.png) 2. Now, please add the `Authorized JavaScript origins`. This should include all the addresses that you might use for your app. In might case, I will **ONLY** use localhost, but since I use a custom port I have to add both `http://localhost` and `http://localhost:5173` 1. Please click on `add URI` ![Authorized JavaScript origins section with ADD URI button](/social-login-assets/google_cons_authorized_js_add_btn.png) 2. Please type your URL ![ADD URI dialog with localhost URL entered](/social-login-assets/google_cons_authorized_js_typed_url.png) 3. Please repeat until you added all the URLs 4. When you finish, your screen should look something like this ![Authorized JavaScript origins with multiple localhost URLs added](/social-login-assets/google_cons_authorized_js_final.png) 3. Now, please add some `Authorized redirect URIs`. This will depend on what page do you depend to use the CapacitorSocialLogin plugin on. In my case, I am going to be using it on `http://localhost:5173/auth` 1. Please click on `ADD URI` ![Authorized redirect URIs section with ADD URI button](/social-login-assets/google_cons_web_add_redirect_url_1.png) 2. Enter your URL and click `ADD URL` again ![ADD URI dialog with redirect URL entered](/social-login-assets/google_cons_web_add_redirect_url_2.png) 4. Click `save` ![Save button at bottom of web client configuration](/social-login-assets/google_cons_web_app_save.png) 3. Now, you should be ready to call `login` from JavaScript like so: 1. First, import `SocialLogin` ```typescript import { SocialLogin } from '@capgo/capacitor-social-login'; ``` 2. Then, call initialize. This should be called ONLY once. ```typescript // onMounted is Vue specific // webClientId is the client ID you got in the web client creation step not the android client ID. onMounted(() => { SocialLogin.initialize({ google: { webClientId: '673324426943-avl4v9ubdas7a0u7igf7in03pdj1dkmg.apps.googleusercontent.com', } }) }) ``` Web Redirect Handling When using Google login on web, you **MUST** call any function from the plugin when the redirect happens to initialize the plugin so it can handle the redirect and close the popup window. You can call either `isLoggedIn()` OR `initialize()` - both will trigger the redirect handling: ```typescript // Option 1: Call isLoggedIn when the redirect page loads SocialLogin.isLoggedIn({ provider: 'google' }).catch(() => { // Ignore the result, this is just to initialize the plugin }); // Option 2: Call initialize when the redirect page loads SocialLogin.initialize({ google: { webClientId: 'YOUR_WEB_CLIENT_ID.apps.googleusercontent.com', } }).catch(() => { // Ignore any errors, this is just to handle the redirect }); ``` Caution On Web, `SocialLogin.refresh({ provider: 'google' })` is not implemented, even when using `google.mode: 'online'`. If you need a fresh Google token on Web, call `SocialLogin.login({ provider: 'google', ... })` again. 3. Create a login button that calls `SocialLogin.login` when clicked ```typescript const res = await SocialLogin.login({ provider: 'google', options: {} }) // Handle the response console.log(JSON.stringify(res)); ``` # Integrations > Backend and auth-platform integrations for @capgo/capacitor-social-login, including Better Auth, Firebase, Supabase, and OAuth providers such as Auth0, Okta, Cognito, and Keycloak. ## Overview [Section titled “Overview”](#overview) These guides show how to combine `@capgo/capacitor-social-login` with backend authentication platforms and session layers. Use these when you want native mobile login on the device but still want a backend or auth service to own users, sessions, and token verification. ## OAuth provider integrations [Section titled “OAuth provider integrations”](#oauth-provider-integrations) [ Auth0](/docs/plugins/social-login/integrations/auth0/) [Auth Connect preset and direct OAuth2 examples.](/docs/plugins/social-login/integrations/auth0/) [ Microsoft Entra ID](/docs/plugins/social-login/integrations/azure/) [Azure preset support and direct OAuth2 configuration.](/docs/plugins/social-login/integrations/azure/) [ AWS Cognito](/docs/plugins/social-login/integrations/cognito/) [Cognito preset and direct endpoint examples.](/docs/plugins/social-login/integrations/cognito/) [ GitHub](/docs/plugins/social-login/integrations/github/) [Generic OAuth2 configuration for GitHub login.](/docs/plugins/social-login/integrations/github/) [ Keycloak](/docs/plugins/social-login/integrations/keycloak/) [OIDC discovery and direct endpoint examples.](/docs/plugins/social-login/integrations/keycloak/) [ Okta](/docs/plugins/social-login/integrations/okta/) [Okta preset and direct OAuth2 examples.](/docs/plugins/social-login/integrations/okta/) [ OneLogin](/docs/plugins/social-login/integrations/onelogin/) [OneLogin preset and direct endpoint examples.](/docs/plugins/social-login/integrations/onelogin/) ## Backend and session integrations [Section titled “Backend and session integrations”](#backend-and-session-integrations) [ Better Auth](/docs/plugins/social-login/better-auth/) [Native token handoff examples for Google, Apple, Facebook, and Generic OAuth guidance.](/docs/plugins/social-login/better-auth/) [ Firebase](/docs/plugins/social-login/firebase/introduction/) [Use native provider login with Firebase Authentication and Firestore.](/docs/plugins/social-login/firebase/introduction/) [ Supabase](/docs/plugins/social-login/supabase/introduction/) [Use native provider login with Supabase Auth and PostgreSQL.](/docs/plugins/social-login/supabase/introduction/) # Auth0 > Integrate Auth0 with @capgo/capacitor-social-login using the Auth Connect preset wrapper or direct OAuth2 configuration. ## Overview [Section titled “Overview”](#overview) `@capgo/capacitor-social-login` supports Auth0 in two ways: * `SocialLoginAuthConnect` with the `auth0` preset * Direct `oauth2` configuration if you want full control over endpoints ## Auth Connect preset example [Section titled “Auth Connect preset example”](#auth-connect-preset-example) ```typescript import { SocialLoginAuthConnect } from '@capgo/capacitor-social-login'; await SocialLoginAuthConnect.initialize({ authConnect: { auth0: { domain: 'https://your-tenant.auth0.com', clientId: 'your-auth0-client-id', redirectUrl: 'myapp://oauth/auth0', audience: 'https://your-api.example.com', }, }, }); const result = await SocialLoginAuthConnect.login({ provider: 'auth0', }); ``` ## Direct OAuth2 example [Section titled “Direct OAuth2 example”](#direct-oauth2-example) ```typescript import { SocialLogin } from '@capgo/capacitor-social-login'; await SocialLogin.initialize({ oauth2: { auth0: { appId: 'your-auth0-client-id', authorizationBaseUrl: 'https://your-tenant.auth0.com/authorize', accessTokenEndpoint: 'https://your-tenant.auth0.com/oauth/token', redirectUrl: 'myapp://oauth/auth0', scope: 'openid profile email offline_access', pkceEnabled: true, additionalParameters: { audience: 'https://your-api.example.com', }, logoutUrl: 'https://your-tenant.auth0.com/v2/logout', }, }, }); const result = await SocialLogin.login({ provider: 'oauth2', options: { providerId: 'auth0', }, }); ``` ## Related docs [Section titled “Related docs”](#related-docs) * [OAuth2 and OIDC providers](/docs/plugins/social-login/oauth2/) * [Ionic Auth Connect migration](/docs/plugins/social-login/migrations/ionic-auth-connect/) * [Better Auth integration](/docs/plugins/social-login/better-auth/) # Microsoft Entra ID > Integrate Microsoft Entra ID or Azure AD with @capgo/capacitor-social-login using the Auth Connect preset wrapper or direct OAuth2 configuration. ## Overview [Section titled “Overview”](#overview) Microsoft Entra ID is supported through: * The `azure` Auth Connect preset * Direct `oauth2` configuration against Microsoft identity endpoints ## Auth Connect preset example [Section titled “Auth Connect preset example”](#auth-connect-preset-example) ```typescript import { SocialLoginAuthConnect } from '@capgo/capacitor-social-login'; await SocialLoginAuthConnect.initialize({ authConnect: { azure: { tenantId: 'common', clientId: 'your-azure-client-id', redirectUrl: 'myapp://oauth/azure', }, }, }); const result = await SocialLoginAuthConnect.login({ provider: 'azure', }); ``` ## Direct OAuth2 example [Section titled “Direct OAuth2 example”](#direct-oauth2-example) ```typescript import { SocialLogin } from '@capgo/capacitor-social-login'; await SocialLogin.initialize({ oauth2: { azure: { appId: 'your-azure-client-id', authorizationBaseUrl: 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize', accessTokenEndpoint: 'https://login.microsoftonline.com/common/oauth2/v2.0/token', redirectUrl: 'myapp://oauth/azure', scope: 'openid profile email User.Read', pkceEnabled: true, resourceUrl: 'https://graph.microsoft.com/v1.0/me', }, }, }); const result = await SocialLogin.login({ provider: 'oauth2', options: { providerId: 'azure', }, }); ``` ## Notes [Section titled “Notes”](#notes) * Replace `common` with your tenant ID for single-tenant apps. * `resourceUrl` can point to Microsoft Graph when you want profile data immediately after login. ## Related docs [Section titled “Related docs”](#related-docs) * [OAuth2 and OIDC providers](/docs/plugins/social-login/oauth2/) * [Ionic Auth Connect migration](/docs/plugins/social-login/migrations/ionic-auth-connect/) * [Better Auth integration](/docs/plugins/social-login/better-auth/) # AWS Cognito > Integrate Amazon Cognito with @capgo/capacitor-social-login using the Auth Connect preset wrapper or direct OAuth2 configuration. ## Overview [Section titled “Overview”](#overview) Amazon Cognito is supported through the `cognito` Auth Connect preset. You can also configure it manually with direct OAuth2 endpoints. ## Auth Connect preset example [Section titled “Auth Connect preset example”](#auth-connect-preset-example) ```typescript import { SocialLoginAuthConnect } from '@capgo/capacitor-social-login'; await SocialLoginAuthConnect.initialize({ authConnect: { cognito: { domain: 'https://your-domain.auth.region.amazoncognito.com', clientId: 'your-cognito-client-id', redirectUrl: 'myapp://oauth/cognito', }, }, }); const result = await SocialLoginAuthConnect.login({ provider: 'cognito', }); ``` ## Direct OAuth2 example [Section titled “Direct OAuth2 example”](#direct-oauth2-example) ```typescript import { SocialLogin } from '@capgo/capacitor-social-login'; await SocialLogin.initialize({ oauth2: { cognito: { appId: 'your-cognito-client-id', authorizationBaseUrl: 'https://your-domain.auth.region.amazoncognito.com/oauth2/authorize', accessTokenEndpoint: 'https://your-domain.auth.region.amazoncognito.com/oauth2/token', redirectUrl: 'myapp://oauth/cognito', scope: 'openid profile email', pkceEnabled: true, resourceUrl: 'https://your-domain.auth.region.amazoncognito.com/oauth2/userInfo', logoutUrl: 'https://your-domain.auth.region.amazoncognito.com/logout', }, }, }); const result = await SocialLogin.login({ provider: 'oauth2', options: { providerId: 'cognito', }, }); ``` ## Related docs [Section titled “Related docs”](#related-docs) * [Ionic Auth Connect migration](/docs/plugins/social-login/migrations/ionic-auth-connect/) * [OAuth2 and OIDC providers](/docs/plugins/social-login/oauth2/) # GitHub > Integrate GitHub OAuth with @capgo/capacitor-social-login using the built-in generic OAuth2 provider. ## Overview [Section titled “Overview”](#overview) GitHub is supported through the built-in generic `oauth2` provider. ## Example [Section titled “Example”](#example) ```typescript import { SocialLogin } from '@capgo/capacitor-social-login'; await SocialLogin.initialize({ oauth2: { github: { appId: 'your-github-client-id', authorizationBaseUrl: 'https://github.com/login/oauth/authorize', accessTokenEndpoint: 'https://github.com/login/oauth/access_token', redirectUrl: 'myapp://oauth/github', scope: 'read:user user:email', pkceEnabled: true, resourceUrl: 'https://api.github.com/user', }, }, }); const result = await SocialLogin.login({ provider: 'oauth2', options: { providerId: 'github', }, }); console.log(result.result.accessToken?.token); console.log(result.result.resourceData); ``` ## Related docs [Section titled “Related docs”](#related-docs) * [OAuth2 and OIDC providers](/docs/plugins/social-login/oauth2/) * [Better Auth integration](/docs/plugins/social-login/better-auth/) # Keycloak > Integrate Keycloak with @capgo/capacitor-social-login using OIDC discovery or direct OAuth2 endpoint configuration. ## Overview [Section titled “Overview”](#overview) Keycloak works best through the built-in `oauth2` provider with OIDC discovery via `issuerUrl`. ## OIDC discovery example [Section titled “OIDC discovery example”](#oidc-discovery-example) ```typescript import { SocialLogin } from '@capgo/capacitor-social-login'; await SocialLogin.initialize({ oauth2: { keycloak: { issuerUrl: 'https://sso.example.com/realms/mobile', clientId: 'mobile-app', redirectUrl: 'myapp://oauth/keycloak', scope: 'openid profile email offline_access', pkceEnabled: true, }, }, }); const result = await SocialLogin.login({ provider: 'oauth2', options: { providerId: 'keycloak', }, }); ``` ## Direct endpoint example [Section titled “Direct endpoint example”](#direct-endpoint-example) ```typescript await SocialLogin.initialize({ oauth2: { keycloak: { appId: 'mobile-app', authorizationBaseUrl: 'https://sso.example.com/realms/mobile/protocol/openid-connect/auth', accessTokenEndpoint: 'https://sso.example.com/realms/mobile/protocol/openid-connect/token', redirectUrl: 'myapp://oauth/keycloak', scope: 'openid profile email offline_access', pkceEnabled: true, resourceUrl: 'https://sso.example.com/realms/mobile/protocol/openid-connect/userinfo', logoutUrl: 'https://sso.example.com/realms/mobile/protocol/openid-connect/logout', }, }, }); ``` ## Related docs [Section titled “Related docs”](#related-docs) * [OAuth2 and OIDC providers](/docs/plugins/social-login/oauth2/) * [Better Auth integration](/docs/plugins/social-login/better-auth/) # Okta > Integrate Okta with @capgo/capacitor-social-login using the Auth Connect preset wrapper or direct OAuth2 configuration. ## Overview [Section titled “Overview”](#overview) Okta is supported through: * The `okta` Auth Connect preset * Direct `oauth2` configuration against your Okta issuer ## Auth Connect preset example [Section titled “Auth Connect preset example”](#auth-connect-preset-example) ```typescript import { SocialLoginAuthConnect } from '@capgo/capacitor-social-login'; await SocialLoginAuthConnect.initialize({ authConnect: { okta: { issuer: 'https://dev-12345.okta.com/oauth2/default', clientId: 'your-okta-client-id', redirectUrl: 'myapp://oauth/okta', }, }, }); const result = await SocialLoginAuthConnect.login({ provider: 'okta', }); ``` ## Direct OAuth2 example [Section titled “Direct OAuth2 example”](#direct-oauth2-example) ```typescript import { SocialLogin } from '@capgo/capacitor-social-login'; await SocialLogin.initialize({ oauth2: { okta: { appId: 'your-okta-client-id', authorizationBaseUrl: 'https://your-domain.okta.com/oauth2/default/v1/authorize', accessTokenEndpoint: 'https://your-domain.okta.com/oauth2/default/v1/token', redirectUrl: 'myapp://oauth/okta', scope: 'openid profile email offline_access', pkceEnabled: true, resourceUrl: 'https://your-domain.okta.com/oauth2/default/v1/userinfo', }, }, }); const result = await SocialLogin.login({ provider: 'oauth2', options: { providerId: 'okta', }, }); ``` ## Related docs [Section titled “Related docs”](#related-docs) * [Ionic Auth Connect migration](/docs/plugins/social-login/migrations/ionic-auth-connect/) * [OAuth2 and OIDC providers](/docs/plugins/social-login/oauth2/) * [Better Auth integration](/docs/plugins/social-login/better-auth/) # OneLogin > Integrate OneLogin with @capgo/capacitor-social-login using the Auth Connect preset wrapper or direct OAuth2 configuration. ## Overview [Section titled “Overview”](#overview) OneLogin is supported through the `onelogin` Auth Connect preset. You can also configure it manually using direct OAuth2 endpoints. ## Auth Connect preset example [Section titled “Auth Connect preset example”](#auth-connect-preset-example) ```typescript import { SocialLoginAuthConnect } from '@capgo/capacitor-social-login'; await SocialLoginAuthConnect.initialize({ authConnect: { onelogin: { issuer: 'https://your-tenant.onelogin.com/oidc/2', clientId: 'your-onelogin-client-id', redirectUrl: 'myapp://oauth/onelogin', }, }, }); const result = await SocialLoginAuthConnect.login({ provider: 'onelogin', }); ``` ## Direct OAuth2 example [Section titled “Direct OAuth2 example”](#direct-oauth2-example) ```typescript import { SocialLogin } from '@capgo/capacitor-social-login'; await SocialLogin.initialize({ oauth2: { onelogin: { appId: 'your-onelogin-client-id', authorizationBaseUrl: 'https://your-tenant.onelogin.com/oidc/2/auth', accessTokenEndpoint: 'https://your-tenant.onelogin.com/oidc/2/token', redirectUrl: 'myapp://oauth/onelogin', scope: 'openid profile email', pkceEnabled: true, resourceUrl: 'https://your-tenant.onelogin.com/oidc/2/me', logoutUrl: 'https://your-tenant.onelogin.com/oidc/2/logout', }, }, }); const result = await SocialLogin.login({ provider: 'oauth2', options: { providerId: 'onelogin', }, }); ``` ## Related docs [Section titled “Related docs”](#related-docs) * [Ionic Auth Connect migration](/docs/plugins/social-login/migrations/ionic-auth-connect/) * [OAuth2 and OIDC providers](/docs/plugins/social-login/oauth2/) # Apple Sign-In Migration to @capgo/social-login > This comprehensive guide provides detailed instructions for transitioning from the @capacitor-community/apple-sign-in plugin to the @capgo/capacitor-social-login plugin, ensuring a smooth migration process and improved capabilities. ## Overview [Section titled “Overview”](#overview) This guide outlines the transition from the legacy `@capacitor-community/apple-sign-in` plugin to the modern `@capgo/capacitor-social-login` package. The new plugin provides a unified interface for multiple social authentication providers with improved TypeScript support and active maintenance. ## Installation [Section titled “Installation”](#installation) 1. Remove the old package: ```bash npm uninstall @capacitor-community/apple-sign-in ``` 2. Install the new package: ```bash npm install @capgo/capacitor-social-login npx cap sync ``` ## Code Changes [Section titled “Code Changes”](#code-changes) ### Import Changes [Section titled “Import Changes”](#import-changes) ```diff import { SignInWithApple } from '@capacitor-community/apple-sign-in'; import { SocialLogin } from '@capgo/capacitor-social-login'; ``` ### Initialization [Section titled “Initialization”](#initialization) **Key Change**: The new plugin requires an initialization step that wasn’t needed before. ```diff // No initialization needed in old package // For iOS: Basic configuration await SocialLogin.initialize({ apple: {} // Basic iOS configuration }); // For Android: Additional configuration required await SocialLogin.initialize({ apple: { clientId: 'YOUR_SERVICE_ID', // Service ID from Apple Developer Portal redirectUrl: 'https://your-backend.com/callback' // Your backend callback URL } }); ``` **Important Note**: For iOS, you provide basic configuration, while Android requires additional details including a Service ID and backend callback URL for web-based OAuth authentication. ### Sign In [Section titled “Sign In”](#sign-in) The login process simplifies from multiple parameters to a cleaner API: ```diff const result = await SignInWithApple.authorize({ clientId: 'com.your.app', redirectURI: 'https://your-app.com/callback', scopes: 'email name', state: '12345', nonce: 'nonce' }); const result = await SocialLogin.login({ provider: 'apple', options: { // Optional: Add scopes if needed scopes: ['email', 'name'], nonce: 'nonce' } }); ``` The new plugin uses `login()` with `provider: 'apple'` and optional scopes rather than passing individual configuration values like `clientId` and `redirectURI`. ### Response Type Changes [Section titled “Response Type Changes”](#response-type-changes) Results now include an `accessToken` object with expiration details and a structured `profile` section, replacing the flatter response format of the original package: ```typescript // Old response type interface AppleSignInResponse { response: { user: string; email: string | null; givenName: string | null; familyName: string | null; identityToken: string | null; authorizationCode: string | null; }; } // New response type interface SocialLoginResponse { provider: 'apple'; result: { accessToken: { token: string; expiresIn?: number; refreshToken?: string; } | null; idToken: string | null; profile: { user: string; email: string | null; givenName: string | null; familyName: string | null; }; }; } ``` ### New Capabilities [Section titled “New Capabilities”](#new-capabilities) The updated plugin introduces functionality that wasn’t available in the predecessor: **Checking Login Status** ```diff // Not available in old package const status = await SocialLogin.isLoggedIn({ provider: 'apple' }); ``` **Logout Functionality** ```diff // Not available in old package await SocialLogin.logout({ provider: 'apple' }); ``` These methods provide `isLoggedIn()` to verify authentication status and `logout()` functionality. ## Platform Specific Changes [Section titled “Platform Specific Changes”](#platform-specific-changes) ### iOS Setup [Section titled “iOS Setup”](#ios-setup) **iOS** maintains familiar setup procedures through Xcode capabilities: 1. The iOS setup remains largely the same. You still need to: * Enable “Sign In with Apple” capability in Xcode * Configure your app in the Apple Developer Portal * No additional code changes required for iOS ### Android Setup [Section titled “Android Setup”](#android-setup) **Android** now receives native support via web-based OAuth authentication: The new plugin provides Android support out of the box, but requires additional setup: 1. Create a Services ID in the Apple Developer Portal 2. Configure a web authentication endpoint 3. Set up your Android app to handle the OAuth flow 4. Backend service configuration is required For detailed Android setup instructions, please refer to the [Android Setup Guide](/docs/plugins/social-login/apple/android/). ## Key Advantages [Section titled “Key Advantages”](#key-advantages) The modernized package provides: 1. **Unified APIs** across multiple social providers (Google, Facebook, Apple) 2. **Improved TypeScript typing** with better type definitions 3. **Active community maintenance** compared to the deprecated version 4. **Built-in Android support** through web-based authentication 5. **Persistent login state management** 6. **Better error handling** with consistent error types ## Breaking Changes [Section titled “Breaking Changes”](#breaking-changes) 1. **Explicit initialization is now required** - no default configuration 2. **Response object structure has changed** - nested result format 3. **Android implementation requires a backend service** for OAuth 4. **Token refresh handling is different** - improved token management 5. **Error handling and error types have changed** - more detailed errors For more detailed setup instructions, please refer to the [official documentation](/docs/plugins/social-login/apple/general/). # Facebook Login Migration to @capgo/social-login > This detailed guide provides step-by-step instructions for transitioning from the @capacitor-community/facebook-login plugin to the @capgo/capacitor-social-login plugin, ensuring a smooth migration process with enhanced features. ## Overview [Section titled “Overview”](#overview) This guide provides comprehensive instructions for migrating from `@capacitor-community/facebook-login` to `@capgo/capacitor-social-login`. The new plugin modernizes Facebook authentication with a unified API that supports multiple social providers, improved TypeScript support, and enhanced capabilities. ## Installation [Section titled “Installation”](#installation) 1. Remove the old package: ```bash npm uninstall @capacitor-community/facebook-login ``` 2. Install the new package: ```bash npm install @capgo/capacitor-social-login npx cap sync ``` ## Code Changes [Section titled “Code Changes”](#code-changes) ### Import Changes [Section titled “Import Changes”](#import-changes) ```diff import { FacebookLogin } from '@capacitor-community/facebook-login'; import { SocialLogin } from '@capgo/capacitor-social-login'; ``` ### Initialization [Section titled “Initialization”](#initialization) **Key Change**: The new package requires explicit setup in your code: ```diff // Old package required no explicit initialization in code // Configuration was done only in native platforms // New package requires explicit initialization await SocialLogin.initialize({ facebook: { appId: 'YOUR_FACEBOOK_APP_ID', // Required for web and Android clientToken: 'YOUR_CLIENT_TOKEN' // Required for Android } }); ``` ### Login [Section titled “Login”](#login) The login method now accepts a provider parameter: ```diff const FACEBOOK_PERMISSIONS = ['email', 'public_profile']; const result = await FacebookLogin.login({ permissions: FACEBOOK_PERMISSIONS }); const result = await SocialLogin.login({ provider: 'facebook', options: { permissions: ['email', 'public_profile'], limitedLogin: false, nonce: 'optional_nonce' } }); ``` ### Response Type Changes [Section titled “Response Type Changes”](#response-type-changes) The response structure has been modernized with a more comprehensive profile object: ```typescript // Old response type interface FacebookLoginResponse { accessToken: { applicationId: string; userId: string; token: string; expires: string; }; recentlyGrantedPermissions: string[]; recentlyDeniedPermissions: string[]; } // New response type interface FacebookLoginResponse { provider: 'facebook'; result: { accessToken: { token: string; applicationId?: string; expires?: string; userId?: string; permissions?: string[]; declinedPermissions?: string[]; } | null; idToken: string | null; profile: { userID: string; email: string | null; friendIDs: string[]; birthday: string | null; ageRange: { min?: number; max?: number } | null; gender: string | null; location: { id: string; name: string } | null; hometown: { id: string; name: string } | null; profileURL: string | null; name: string | null; imageURL: string | null; }; }; } ``` **Key Differences**: * Response now includes a `provider` field identifying the authentication provider * More detailed `profile` object with additional user information * Consistent structure across all social login providers ### Checking Login Status [Section titled “Checking Login Status”](#checking-login-status) ```diff const result = await FacebookLogin.getCurrentAccessToken(); const isLoggedIn = result && result.accessToken; const status = await SocialLogin.isLoggedIn({ provider: 'facebook' }); const isLoggedIn = status.isLoggedIn; ``` ### Logout [Section titled “Logout”](#logout) ```diff await FacebookLogin.logout(); await SocialLogin.logout({ provider: 'facebook' }); ``` ## Platform Specific Changes [Section titled “Platform Specific Changes”](#platform-specific-changes) ### Android Setup [Section titled “Android Setup”](#android-setup) Configuration is now handled through the initialize method: ```diff // AndroidManifest.xml changes remain the same // strings.xml become irrelevant // Additionally initialize in your code: await SocialLogin.initialize({ facebook: { appId: 'your-app-id', clientToken: 'your-client-token' // New requirement } }); ``` **Important**: Client token is now required for Android authentication. ### iOS Setup [Section titled “iOS Setup”](#ios-setup) 1. The iOS setup in `AppDelegate.swift` remains the same: ```swift import FBSDKCoreKit // In application:didFinishLaunchingWithOptions: FBSDKCoreKit.ApplicationDelegate.shared.application( application, didFinishLaunchingWithOptions: launchOptions ) // In application:openURL:options: ApplicationDelegate.shared.application( app, open: url, sourceApplication: options[UIApplication.OpenURLOptionsKey.sourceApplication] as? String, annotation: options[UIApplication.OpenURLOptionsKey.annotation] ) ``` 2. The `Info.plist` configuration remains the same: ```xml <key>CFBundleURLTypes</key> <array> <dict> <key>CFBundleURLSchemes</key> <array> <string>fb[APP_ID]</string> </array> </dict> </array> <key>FacebookAppID</key> <string>[APP_ID]</string> <key>FacebookClientToken</key> <string>[CLIENT_TOKEN]</string> <key>FacebookDisplayName</key> <string>[APP_NAME]</string> <key>LSApplicationQueriesSchemes</key> <array> <string>fbapi</string> <string>fbauth</string> <string>fb-messenger-share-api</string> <string>fbauth2</string> <string>fbshareextension</string> </array> ``` ## Breaking Changes [Section titled “Breaking Changes”](#breaking-changes) Summary of breaking changes when migrating: 1. **Explicit initialization is now required** - Must call `initialize()` before use 2. **Response object structure has changed significantly** - New nested result format with enhanced profile data 3. **Client token is now required for Android** - Additional configuration needed 4. **Different method names and parameter structures** - Provider-based approach 5. **Error handling and error types have changed** - More detailed error information ## Key Advantages [Section titled “Key Advantages”](#key-advantages) The new plugin provides: * **Unified API** across multiple social providers (Google, Apple, Facebook) * **Improved TypeScript support** with better type definitions * **Enhanced profile data** with more user information * **Active maintenance** and community support * **Consistent error handling** across all providers * **Better token management** with proper expiration handling For more detailed setup instructions, please refer to the [official documentation](/docs/plugins/social-login/facebook/). # Google Auth Migration to @capgo/social-login > This guide outlines transitioning from the older Google Auth plugin to the newer Capgo social login package, which unifies multiple social authentication providers. ## Overview [Section titled “Overview”](#overview) This guide provides comprehensive steps for migrating from `@codetrix-studio/capacitor-google-auth` to `@capgo/capacitor-social-login`, ensuring a smooth transition and improved authentication experience. The new plugin unifies multiple social authentication providers under a single, consistent API. ## Installation [Section titled “Installation”](#installation) 1. Remove the old package: ```bash npm uninstall @codetrix-studio/capacitor-google-auth ``` 2. Install the new package: ```bash npm install @capgo/capacitor-social-login npx cap sync ``` ## Important Changes in Google Auth Setup [Section titled “Important Changes in Google Auth Setup”](#important-changes-in-google-auth-setup) ### Web Client ID Requirement [Section titled “Web Client ID Requirement”](#web-client-id-requirement) **Critical Change**: The updated plugin requires using a Web Client ID across all platforms. You’ll need to: 1. Create a Web Client ID in Google Cloud Console if you don’t have one ([How to get the credentials](/docs/plugins/social-login/google/general/)) 2. Use this Web Client ID in the `webClientId` field for all platforms 3. For Android, you still need to create an Android Client ID with your SHA1, but this is only for verification purposes - the token won’t be used ([Android setup guide](/docs/plugins/social-login/google/android/)) ## Code Changes [Section titled “Code Changes”](#code-changes) ### Import Changes [Section titled “Import Changes”](#import-changes) ```diff import { GoogleAuth } from '@codetrix-studio/capacitor-google-auth'; import { SocialLogin } from '@capgo/capacitor-social-login'; ``` ### Initialization [Section titled “Initialization”](#initialization) The setup transforms from a simple `GoogleAuth.initialize()` call to a more structured `SocialLogin.initialize()` with nested Google configuration: ```diff GoogleAuth.initialize({ clientId: 'CLIENT_ID.apps.googleusercontent.com', scopes: ['profile', 'email'], grantOfflineAccess: true, }); await SocialLogin.initialize({ google: { webClientId: 'WEB_CLIENT_ID.apps.googleusercontent.com', // Use Web Client ID for all platforms iOSClientId: 'IOS_CLIENT_ID', // for iOS mode: 'offline' // replaces grantOfflineAccess } }); ``` ### Sign In [Section titled “Sign In”](#sign-in) The login method changes from `GoogleAuth.signIn()` to `SocialLogin.login()` with explicit provider specification: ```diff const user = await GoogleAuth.signIn(); const res = await SocialLogin.login({ provider: 'google', options: { scopes: ['email', 'profile'], forceRefreshToken: true // if you need refresh token } }); ``` ## Platform Specific Changes [Section titled “Platform Specific Changes”](#platform-specific-changes) ### Android [Section titled “Android”](#android) 1. Update your `MainActivity.java` ([Full Android setup guide](/docs/plugins/social-login/google/android/)): ```diff import ee.forgr.capacitor.social.login.GoogleProvider; import ee.forgr.capacitor.social.login.SocialLoginPlugin; import ee.forgr.capacitor.social.login.ModifiedMainActivityForSocialLoginPlugin; import com.getcapacitor.PluginHandle; import com.getcapacitor.Plugin; import android.content.Intent; import android.util.Log; public class MainActivity extends BridgeActivity { public class MainActivity extends BridgeActivity implements ModifiedMainActivityForSocialLoginPlugin { @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode >= GoogleProvider.REQUEST_AUTHORIZE_GOOGLE_MIN && requestCode < GoogleProvider.REQUEST_AUTHORIZE_GOOGLE_MAX) { PluginHandle pluginHandle = getBridge().getPlugin("SocialLogin"); if (pluginHandle == null) { Log.i("Google Activity Result", "SocialLogin login handle is null"); return; } Plugin plugin = pluginHandle.getInstance(); if (!(plugin instanceof SocialLoginPlugin)) { Log.i("Google Activity Result", "SocialLogin plugin instance is not SocialLoginPlugin"); return; } ((SocialLoginPlugin) plugin).handleGoogleLoginIntent(requestCode, data); } } public void IHaveModifiedTheMainActivityForTheUseWithSocialLoginPlugin() {} } ``` ### iOS [Section titled “iOS”](#ios) 1. No major changes needed in AppDelegate.swift ([iOS setup guide](/docs/plugins/social-login/google/ios/)) 2. Update your configuration in `capacitor.config.json`, we don’t use it in the new plugin: ```diff { "plugins": { "GoogleAuth": { "scopes": ["profile", "email"], "serverClientId": "xxxxxx-xxxxxxxxxxxxxxxxxx.apps.googleusercontent.com", "forceCodeForRefreshToken": true } } ``` ### Web [Section titled “Web”](#web) 1. Remove the Google Sign-In meta tags from your `index.html` if you were using them: ```diff <meta name="google-signin-client_id" content="{your client id here}" /> <meta name="google-signin-scope" content="profile email" /> ``` ## Response Type Changes [Section titled “Response Type Changes”](#response-type-changes) The authentication response now provides a structured object containing provider information, access tokens, ID tokens, and user profile data: ```typescript interface GoogleLoginResponse { provider: 'google'; result: { accessToken: { token: string; expires: string; // ... other token fields } | null; idToken: string | null; profile: { email: string | null; familyName: string | null; givenName: string | null; id: string | null; name: string | null; imageUrl: string | null; }; }; } ``` The response structure includes: * **provider**: Identifies the authentication provider (`'google'`) * **result.accessToken**: Access token details with expiration * **result.idToken**: ID token for authentication * **result.profile**: User profile information including email, name, and image URL ## Additional Capabilities [Section titled “Additional Capabilities”](#additional-capabilities) The new package supports multiple social authentication providers beyond Google: * [Apple Sign-In](/docs/plugins/social-login/apple/general/) * [Facebook Login](/docs/plugins/social-login/facebook/) This unified approach provides: * Consistent API across all providers * Improved TypeScript support * Better error handling * Active maintenance and community support Check the [main documentation](/docs/plugins/social-login/google/general/) for detailed setup instructions for these additional providers. # Ionic Auth Connect Migration to @capgo/capacitor-social-login > Migrate from Ionic Auth Connect to Capgo Social Login with OAuth2 and provider-native sign-in. ## Overview [Section titled “Overview”](#overview) Capgo Social Login replaces Ionic Auth Connect with a provider-native OAuth2 flow for Google, Apple, Facebook, and other identity providers. It supports multiple providers in one plugin and works across iOS, Android, and Web. ## Why this works [Section titled “Why this works”](#why-this-works) The plugin includes an Auth Connect compatibility wrapper named `SocialLoginAuthConnect`. It maps familiar Ionic Auth Connect provider IDs onto the built-in OAuth2 engine, so you can keep using names such as `auth0`, `azure`, and `okta`. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-social-login bunx cap sync ``` ## Replace your imports [Section titled “Replace your imports”](#replace-your-imports) ```typescript // Before import { AuthConnect } from '@ionic-enterprise/auth-connect'; // After import { SocialLoginAuthConnect } from '@capgo/capacitor-social-login'; ``` ## Initialize providers [Section titled “Initialize providers”](#initialize-providers) Use the `authConnect` presets when you want the same provider IDs that Ionic Auth Connect used: ```typescript await SocialLoginAuthConnect.initialize({ authConnect: { auth0: { domain: 'https://your-tenant.auth0.com', clientId: 'your-auth0-client-id', redirectUrl: 'myapp://oauth/auth0', audience: 'https://your-api.example.com', }, azure: { tenantId: 'common', clientId: 'your-azure-client-id', redirectUrl: 'myapp://oauth/azure', }, cognito: { domain: 'https://your-domain.auth.region.amazoncognito.com', clientId: 'your-cognito-client-id', redirectUrl: 'myapp://oauth/cognito', }, okta: { issuer: 'https://dev-12345.okta.com/oauth2/default', clientId: 'your-okta-client-id', redirectUrl: 'myapp://oauth/okta', }, onelogin: { issuer: 'https://your-tenant.onelogin.com/oidc/2', clientId: 'your-onelogin-client-id', redirectUrl: 'myapp://oauth/onelogin', }, }, }); ``` ## Supported provider IDs [Section titled “Supported provider IDs”](#supported-provider-ids) * `auth0` * `azure` * `cognito` * `okta` * `onelogin` ## Login, logout, and token access [Section titled “Login, logout, and token access”](#login-logout-and-token-access) ```typescript const result = await SocialLoginAuthConnect.login({ provider: 'auth0', }); const status = await SocialLoginAuthConnect.isLoggedIn({ provider: 'auth0', }); const code = await SocialLoginAuthConnect.getAuthorizationCode({ provider: 'auth0', }); await SocialLoginAuthConnect.logout({ provider: 'auth0', }); ``` ## Provider-specific preset examples [Section titled “Provider-specific preset examples”](#provider-specific-preset-examples) ### Auth0 preset example [Section titled “Auth0 preset example”](#auth0-preset-example) ```typescript await SocialLoginAuthConnect.initialize({ authConnect: { auth0: { domain: 'https://your-tenant.auth0.com', clientId: 'your-auth0-client-id', redirectUrl: 'myapp://oauth/auth0', audience: 'https://your-api.example.com', }, }, }); const auth0Result = await SocialLoginAuthConnect.login({ provider: 'auth0', }); console.log(auth0Result.result.idToken); ``` ### Azure preset example [Section titled “Azure preset example”](#azure-preset-example) ```typescript await SocialLoginAuthConnect.initialize({ authConnect: { azure: { tenantId: 'common', clientId: 'your-azure-client-id', redirectUrl: 'myapp://oauth/azure', }, }, }); const azureResult = await SocialLoginAuthConnect.login({ provider: 'azure', }); console.log(azureResult.result.resourceData); ``` ### Cognito preset example [Section titled “Cognito preset example”](#cognito-preset-example) ```typescript await SocialLoginAuthConnect.initialize({ authConnect: { cognito: { domain: 'https://your-domain.auth.region.amazoncognito.com', clientId: 'your-cognito-client-id', redirectUrl: 'myapp://oauth/cognito', }, }, }); const cognitoResult = await SocialLoginAuthConnect.login({ provider: 'cognito', }); console.log(cognitoResult.result.idToken); ``` ### Okta preset example [Section titled “Okta preset example”](#okta-preset-example) ```typescript await SocialLoginAuthConnect.initialize({ authConnect: { okta: { issuer: 'https://dev-12345.okta.com/oauth2/default', clientId: 'your-okta-client-id', redirectUrl: 'myapp://oauth/okta', }, }, }); const oktaResult = await SocialLoginAuthConnect.login({ provider: 'okta', }); console.log(oktaResult.result.resourceData); ``` ### OneLogin preset example [Section titled “OneLogin preset example”](#onelogin-preset-example) ```typescript await SocialLoginAuthConnect.initialize({ authConnect: { onelogin: { issuer: 'https://your-tenant.onelogin.com/oidc/2', clientId: 'your-onelogin-client-id', redirectUrl: 'myapp://oauth/onelogin', }, }, }); const oneloginResult = await SocialLoginAuthConnect.login({ provider: 'onelogin', }); console.log(oneloginResult.result.idToken); ``` ## Overriding endpoints [Section titled “Overriding endpoints”](#overriding-endpoints) Each preset creates a default OAuth2 configuration from `domain` or `issuer`. If your tenant uses custom endpoints, override them directly: ```typescript await SocialLoginAuthConnect.initialize({ authConnect: { onelogin: { issuer: 'https://your-tenant.onelogin.com/oidc/2', clientId: 'your-onelogin-client-id', redirectUrl: 'myapp://oauth/onelogin', authorizationBaseUrl: 'https://your-tenant.onelogin.com/oidc/2/auth', accessTokenEndpoint: 'https://your-tenant.onelogin.com/oidc/2/token', resourceUrl: 'https://your-tenant.onelogin.com/oidc/2/me', logoutUrl: 'https://your-tenant.onelogin.com/oidc/2/logout', }, }, }); ``` ## Direct OAuth2 configuration [Section titled “Direct OAuth2 configuration”](#direct-oauth2-configuration) If you do not want presets, configure the same providers directly in the generic OAuth2 docs: * [OAuth2 and OIDC provider guide](/docs/plugins/social-login/oauth2/) ## Migration notes [Section titled “Migration notes”](#migration-notes) 1. **The compatibility layer is OAuth2-based** It keeps the provider names, not Ionic’s native implementation details. 2. **Refresh tokens still depend on scopes** Request `offline_access` or the provider-specific equivalent when you need refresh tokens. 3. **Custom endpoints can override presets** If the preset is close but not exact, override only the endpoints that differ. 4. **Direct `oauth2` entries win** If you define both `authConnect.auth0` and `oauth2.auth0`, the direct `oauth2` config takes precedence. ## Related Documentation [Section titled “Related Documentation”](#related-documentation) * [Social Login getting started](/docs/plugins/social-login/getting-started/) * [OAuth2 and OIDC providers](/docs/plugins/social-login/oauth2/) * [Migrate from Ionic Auth Connect](/docs/upgrade/from-ionic-auth-connect/) * [Ionic enterprise plugins migration solution](/solutions/ionic-enterprise-plugins/) # V7 Migration Guide > Guide for migrating from earlier versions to V7 of @capgo/capacitor-social-login ## Introduction [Section titled “Introduction”](#introduction) Caution This guide is for the `V1`/`V7` version of the plugin for people who were still using this plugin with the `0.x.x` version. This guide will cover the following: * Migrating to the V1 version from the `main` version * Migrating to the V1 version from the `development` version ## Important changes in V1 [Section titled “Important changes in V1”](#important-changes-in-v1) V1 is just a port of the development version into main. It does, however, include a lot of important changes that are not available in the `main` V0 version. Those changes include: * Access scopes for Google login * Offline mode for Google login * Unification of the different implementations * Extensive testing was conducted to ensure that all implementations of the Google Provider behave in the same way between platforms ## Migration from the V0 main version [Section titled “Migration from the V0 main version”](#migration-from-the-v0-main-version) * Changes in the `MainActivity.java` for Android * Please follow the [Google Setup Guide](/docs/plugins/social-login/google/android/). Specifically, please search for `MainActivity.java` * Please add redirect urls in the Google Console. Without adding redirect urls, Google login will not work. * Again, please follow the [Google Setup Guide](/docs/plugins/social-login/google/android/). Specifically, please search for `Authorized redirect URIs` * Please ensure that you are not using `grantOfflineAccess` in the config. This feature is not supported in V1. * Please ensure that authentication works on all the platforms. ## Migration from the V0 development version [Section titled “Migration from the V0 development version”](#migration-from-the-v0-development-version) * Changes in the `MainActivity.java` for Android * Please follow the [Google Setup Guide](/docs/plugins/social-login/google/android/). Specifically, please search for `MainActivity.java`. In V1, you **HAVE TO** implement `ModifiedMainActivityForSocialLoginPlugin` in your main activity. This change is crucial for the plugin to work * Please add redirect urls in the Google Console. Without adding redirect urls, Google login will not work. * Again, please follow the [Google Setup Guide](/docs/plugins/social-login/google/android/). Specifically, please search for `Authorized redirect URIs` * Please ensure that types and variable names are correct. Please know that types and variables might not match between development and V1. * Please ensure that authentication works on all the platforms. # Generic OAuth2 Providers > Configure GitHub, Azure AD, Auth0, Okta, Keycloak, and other OAuth2 or OIDC providers with the Capgo Social Login plugin. ## Introduction [Section titled “Introduction”](#introduction) The Capgo Social Login plugin includes a built-in OAuth2 and OpenID Connect engine. You can use it to connect any standards-based identity provider, including: * GitHub * Azure AD / Microsoft Entra ID * Auth0 * Okta * Keycloak * Custom OAuth2 or OIDC servers The `oauth2` configuration is multi-provider by design. You can register several providers at once and then select one at login time with `providerId`. ## What you need [Section titled “What you need”](#what-you-need) Before you configure a provider, collect: * Your OAuth client ID * A redirect URL that matches your app scheme or web callback URL * An authorization endpoint * A token endpoint for authorization code flow, or an `issuerUrl` for OIDC discovery * The scopes your app needs, such as `openid profile email` ## Multi-provider configuration [Section titled “Multi-provider configuration”](#multi-provider-configuration) Use `SocialLogin.initialize()` once during app startup and register every provider you need: ```typescript import { SocialLogin } from '@capgo/capacitor-social-login'; await SocialLogin.initialize({ oauth2: { github: { appId: 'your-github-client-id', authorizationBaseUrl: 'https://github.com/login/oauth/authorize', accessTokenEndpoint: 'https://github.com/login/oauth/access_token', redirectUrl: 'myapp://oauth/github', scope: 'read:user user:email', pkceEnabled: true, resourceUrl: 'https://api.github.com/user', }, azure: { appId: 'your-azure-client-id', authorizationBaseUrl: 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize', accessTokenEndpoint: 'https://login.microsoftonline.com/common/oauth2/v2.0/token', redirectUrl: 'myapp://oauth/azure', scope: 'openid profile email User.Read', pkceEnabled: true, resourceUrl: 'https://graph.microsoft.com/v1.0/me', }, auth0: { issuerUrl: 'https://your-tenant.auth0.com', appId: 'your-auth0-client-id', redirectUrl: 'myapp://oauth/auth0', scope: 'openid profile email offline_access', pkceEnabled: true, additionalParameters: { audience: 'https://your-api.example.com', }, }, }, }); ``` ## OIDC discovery and aliases [Section titled “OIDC discovery and aliases”](#oidc-discovery-and-aliases) If your provider exposes an OpenID Connect discovery document, `issuerUrl` is the simplest setup: ```typescript await SocialLogin.initialize({ oauth2: { keycloak: { issuerUrl: 'https://sso.example.com/realms/mobile', clientId: 'mobile-app', redirectUrl: 'myapp://oauth/keycloak', scope: 'openid profile email offline_access', pkceEnabled: true, }, }, }); ``` The plugin also supports common OAuth and OIDC aliases: * `clientId` as an alias of `appId` * `authorizationEndpoint` as an alias of `authorizationBaseUrl` * `tokenEndpoint` as an alias of `accessTokenEndpoint` * `endSessionEndpoint` as an alias of `logoutUrl` * `scopes` as an alias of `scope` Also available: * `additionalParameters` for auth request overrides * `additionalTokenParameters` for token exchange overrides * `additionalResourceHeaders` for custom resource endpoint headers * `additionalLogoutParameters` and `postLogoutRedirectUrl` for logout flows * `loginHint`, `prompt`, and `iosPrefersEphemeralSession` ## Auth Connect-compatible presets [Section titled “Auth Connect-compatible presets”](#auth-connect-compatible-presets) If you are migrating from Ionic Auth Connect and want to keep the same provider names, use `SocialLoginAuthConnect`. ```typescript import { SocialLoginAuthConnect } from '@capgo/capacitor-social-login'; await SocialLoginAuthConnect.initialize({ authConnect: { auth0: { domain: 'https://your-tenant.auth0.com', clientId: 'your-auth0-client-id', redirectUrl: 'myapp://oauth/auth0', audience: 'https://your-api.example.com', }, azure: { tenantId: 'common', clientId: 'your-azure-client-id', redirectUrl: 'myapp://oauth/azure', }, okta: { issuer: 'https://dev-12345.okta.com/oauth2/default', clientId: 'your-okta-client-id', redirectUrl: 'myapp://oauth/okta', }, }, }); ``` Supported preset provider IDs: * `auth0` * `azure` * `cognito` * `okta` * `onelogin` If a provider needs custom endpoints, either override them in the preset or bypass presets and configure the provider directly in `oauth2`. ## Configuration options [Section titled “Configuration options”](#configuration-options) | Option | Type | Required | Description | | ------------------------------------------------ | ------------------------ | -------- | ---------------------------------------------- | | `appId` / `clientId` | string | Yes | OAuth2 client identifier | | `issuerUrl` | string | No | OIDC discovery base URL | | `authorizationBaseUrl` / `authorizationEndpoint` | string | Yes\* | Authorization endpoint URL | | `accessTokenEndpoint` / `tokenEndpoint` | string | No\* | Token endpoint URL | | `redirectUrl` | string | Yes | Callback URL | | `scope` / `scopes` | string / string\[] | No | Requested scopes | | `pkceEnabled` | boolean | No | Defaults to `true` | | `responseType` | `'code'` or `'token'` | No | Defaults to `'code'` | | `resourceUrl` | string | No | User info or resource endpoint | | `logoutUrl` / `endSessionEndpoint` | string | No | Logout or end-session URL | | `postLogoutRedirectUrl` | string | No | Redirect URL after logout | | `additionalParameters` | `Record<string, string>` | No | Extra auth request params | | `additionalTokenParameters` | `Record<string, string>` | No | Extra token request params | | `additionalResourceHeaders` | `Record<string, string>` | No | Extra headers for `resourceUrl` | | `additionalLogoutParameters` | `Record<string, string>` | No | Extra logout params | | `loginHint` | string | No | Shortcut for `additionalParameters.login_hint` | | `prompt` | string | No | Shortcut for `additionalParameters.prompt` | | `iosPrefersEphemeralSession` | boolean | No | Prefer ephemeral browser session on iOS | | `logsEnabled` | boolean | No | Enable verbose debug logging | `authorizationBaseUrl` and `accessTokenEndpoint` are only optional when `issuerUrl` is enough for discovery. Explicit endpoints always win over discovered values. ## Using OAuth2 login [Section titled “Using OAuth2 login”](#using-oauth2-login) ### Login [Section titled “Login”](#login) ```typescript const result = await SocialLogin.login({ provider: 'oauth2', options: { providerId: 'github', scope: 'read:user user:email', loginHint: 'user@example.com', }, }); ``` ### Redirect flow on web [Section titled “Redirect flow on web”](#redirect-flow-on-web) Use `flow: 'redirect'` if you want a full-page redirect instead of a popup: ```typescript await SocialLogin.login({ provider: 'oauth2', options: { providerId: 'auth0', flow: 'redirect', }, }); ``` On the page that receives the callback, parse the login result: ```typescript const result = await SocialLogin.handleRedirectCallback(); if (result?.provider === 'oauth2') { console.log(result.result.providerId); } ``` ### Login status and logout [Section titled “Login status and logout”](#login-status-and-logout) ```typescript const status = await SocialLogin.isLoggedIn({ provider: 'oauth2', providerId: 'github', }); await SocialLogin.logout({ provider: 'oauth2', providerId: 'github', }); ``` ### Refresh tokens [Section titled “Refresh tokens”](#refresh-tokens) ```typescript await SocialLogin.refresh({ provider: 'oauth2', options: { providerId: 'github', }, }); const refreshed = await SocialLogin.refreshToken({ provider: 'oauth2', providerId: 'github', refreshToken: 'existing-refresh-token', }); ``` `refresh()` uses the refresh token stored by the plugin. `refreshToken()` lets you pass a refresh token yourself and returns the fresh OAuth2 response. ### Get the current access token [Section titled “Get the current access token”](#get-the-current-access-token) ```typescript const code = await SocialLogin.getAuthorizationCode({ provider: 'oauth2', providerId: 'github', }); console.log(code.accessToken); ``` ## Provider-specific examples [Section titled “Provider-specific examples”](#provider-specific-examples) ### GitHub example [Section titled “GitHub example”](#github-example) Use GitHub when you want a simple OAuth app flow and basic profile data: ```typescript await SocialLogin.initialize({ oauth2: { github: { appId: 'your-github-client-id', authorizationBaseUrl: 'https://github.com/login/oauth/authorize', accessTokenEndpoint: 'https://github.com/login/oauth/access_token', redirectUrl: 'myapp://oauth/github', scope: 'read:user user:email', pkceEnabled: true, resourceUrl: 'https://api.github.com/user', }, }, }); const githubResult = await SocialLogin.login({ provider: 'oauth2', options: { providerId: 'github', }, }); console.log(githubResult.result.accessToken?.token); console.log(githubResult.result.resourceData); ``` ### Azure AD / Microsoft Entra ID example [Section titled “Azure AD / Microsoft Entra ID example”](#azure-ad--microsoft-entra-id-example) Use Azure when you need Microsoft Graph data such as the user profile: ```typescript await SocialLogin.initialize({ oauth2: { azure: { appId: 'your-azure-client-id', authorizationBaseUrl: 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize', accessTokenEndpoint: 'https://login.microsoftonline.com/common/oauth2/v2.0/token', redirectUrl: 'myapp://oauth/azure', scope: 'openid profile email User.Read', pkceEnabled: true, resourceUrl: 'https://graph.microsoft.com/v1.0/me', }, }, }); const azureResult = await SocialLogin.login({ provider: 'oauth2', options: { providerId: 'azure', }, }); console.log(azureResult.result.idToken); console.log(azureResult.result.resourceData); ``` ### Auth0 example [Section titled “Auth0 example”](#auth0-example) Auth0 is a good fit when you need OIDC plus a custom API audience: ```typescript await SocialLogin.initialize({ oauth2: { auth0: { appId: 'your-auth0-client-id', authorizationBaseUrl: 'https://your-tenant.auth0.com/authorize', accessTokenEndpoint: 'https://your-tenant.auth0.com/oauth/token', redirectUrl: 'myapp://oauth/auth0', scope: 'openid profile email offline_access', pkceEnabled: true, additionalParameters: { audience: 'https://your-api.example.com', }, }, }, }); const auth0Result = await SocialLogin.login({ provider: 'oauth2', options: { providerId: 'auth0', flow: 'redirect', }, }); ``` If you use redirect flow on web, read the result back on the callback page: ```typescript const auth0Result = await SocialLogin.handleRedirectCallback(); if (auth0Result?.provider === 'oauth2') { console.log(auth0Result.result.idToken); } ``` ### Okta example [Section titled “Okta example”](#okta-example) ```typescript await SocialLogin.initialize({ oauth2: { okta: { appId: 'your-okta-client-id', authorizationBaseUrl: 'https://your-domain.okta.com/oauth2/default/v1/authorize', accessTokenEndpoint: 'https://your-domain.okta.com/oauth2/default/v1/token', redirectUrl: 'myapp://oauth/okta', scope: 'openid profile email offline_access', pkceEnabled: true, resourceUrl: 'https://your-domain.okta.com/oauth2/default/v1/userinfo', }, }, }); const oktaResult = await SocialLogin.login({ provider: 'oauth2', options: { providerId: 'okta', }, }); console.log(oktaResult.result.resourceData); ``` ### Keycloak example [Section titled “Keycloak example”](#keycloak-example) Use discovery when your provider publishes `/.well-known/openid-configuration`: ```typescript await SocialLogin.initialize({ oauth2: { keycloak: { issuerUrl: 'https://sso.example.com/realms/mobile', clientId: 'mobile-app', redirectUrl: 'myapp://oauth/keycloak', scope: 'openid profile email offline_access', pkceEnabled: true, }, }, }); const keycloakResult = await SocialLogin.login({ provider: 'oauth2', options: { providerId: 'keycloak', }, }); console.log(keycloakResult.result.idToken); ``` ## OAuth2 response shape [Section titled “OAuth2 response shape”](#oauth2-response-shape) Successful OAuth2 logins return: | Field | Description | | -------------- | ------------------------------------------------ | | `providerId` | The configured provider key used for the login | | `accessToken` | Access token payload or `null` | | `idToken` | OIDC ID token if the provider returned one | | `refreshToken` | Refresh token if the requested scopes allowed it | | `resourceData` | Raw JSON fetched from `resourceUrl` | | `scope` | Granted scopes | | `tokenType` | Usually `bearer` | | `expiresIn` | Token lifetime in seconds | ## Provider setup reference [Section titled “Provider setup reference”](#provider-setup-reference) ### GitHub [Section titled “GitHub”](#github) 1. **Create an OAuth app** Open [GitHub Developer Settings](https://github.com/settings/developers) and create a new OAuth App. 2. **Set the callback URL** Use your app redirect URL, for example `myapp://oauth/github`. 3. **Configure the plugin** ```typescript await SocialLogin.initialize({ oauth2: { github: { appId: 'your-github-client-id', authorizationBaseUrl: 'https://github.com/login/oauth/authorize', accessTokenEndpoint: 'https://github.com/login/oauth/access_token', redirectUrl: 'myapp://oauth/github', scope: 'read:user user:email', pkceEnabled: true, resourceUrl: 'https://api.github.com/user', }, }, }); ``` ### Azure AD / Microsoft Entra ID [Section titled “Azure AD / Microsoft Entra ID”](#azure-ad--microsoft-entra-id) 1. **Register an app** Go to Azure Portal, open `App registrations`, and create a native or mobile app registration. 2. **Add the redirect URI** Add a mobile or desktop redirect URI that matches your app callback URL. 3. **Configure the plugin** ```typescript await SocialLogin.initialize({ oauth2: { azure: { appId: 'your-azure-client-id', authorizationBaseUrl: 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize', accessTokenEndpoint: 'https://login.microsoftonline.com/common/oauth2/v2.0/token', redirectUrl: 'myapp://oauth/azure', scope: 'openid profile email User.Read', pkceEnabled: true, resourceUrl: 'https://graph.microsoft.com/v1.0/me', }, }, }); ``` Note Replace `common` with your tenant ID if your app is single-tenant. ### Auth0 [Section titled “Auth0”](#auth0) 1. **Create a native application** Open the [Auth0 Dashboard](https://manage.auth0.com) and create a Native app. 2. **Set allowed callback URLs** Add the exact redirect URL used by your Capacitor app. 3. **Configure the plugin** ```typescript await SocialLogin.initialize({ oauth2: { auth0: { appId: 'your-auth0-client-id', authorizationBaseUrl: 'https://your-tenant.auth0.com/authorize', accessTokenEndpoint: 'https://your-tenant.auth0.com/oauth/token', redirectUrl: 'myapp://oauth/auth0', scope: 'openid profile email offline_access', pkceEnabled: true, additionalParameters: { audience: 'https://your-api.example.com', }, logoutUrl: 'https://your-tenant.auth0.com/v2/logout', }, }, }); ``` ### Okta [Section titled “Okta”](#okta) 1. **Create an OIDC native app** In Okta Admin Console, create an OIDC Native Application. 2. **Add your redirect URI** Register the exact callback URL used by your app. 3. **Configure the plugin** ```typescript await SocialLogin.initialize({ oauth2: { okta: { appId: 'your-okta-client-id', authorizationBaseUrl: 'https://your-domain.okta.com/oauth2/default/v1/authorize', accessTokenEndpoint: 'https://your-domain.okta.com/oauth2/default/v1/token', redirectUrl: 'myapp://oauth/okta', scope: 'openid profile email offline_access', pkceEnabled: true, resourceUrl: 'https://your-domain.okta.com/oauth2/default/v1/userinfo', }, }, }); ``` ### Keycloak and custom OIDC providers [Section titled “Keycloak and custom OIDC providers”](#keycloak-and-custom-oidc-providers) If your provider supports OpenID Connect discovery, prefer `issuerUrl`: ```typescript await SocialLogin.initialize({ oauth2: { keycloak: { issuerUrl: 'https://sso.example.com/realms/mobile', clientId: 'mobile-app', redirectUrl: 'myapp://oauth/keycloak', scope: 'openid profile email offline_access', pkceEnabled: true, }, }, }); ``` If discovery is not available, configure the authorization and token endpoints manually. ## Platform-specific notes [Section titled “Platform-specific notes”](#platform-specific-notes) ### iOS [Section titled “iOS”](#ios) * The plugin uses `ASWebAuthenticationSession`. * Set `iosPrefersEphemeralSession: true` if you want a private browser session with no shared cookies. ### Android [Section titled “Android”](#android) * OAuth redirects return through your app scheme and host. * Make sure the provider callback URL exactly matches your Android deep link setup. * The plugin already handles the OAuth activity. Only add custom intent filters if your app needs a different redirect pattern. ### Web [Section titled “Web”](#web) * Popup flow is the default and works well for single-page apps. * Redirect flow is better when the provider blocks popups or your auth rules require top-level navigation. * Some providers block direct browser token exchange with CORS. In those cases, use a backend exchange or a provider setup that allows public clients. ## Security best practices [Section titled “Security best practices”](#security-best-practices) 1. **Use PKCE** Keep `pkceEnabled: true` for public clients. 2. **Prefer authorization code flow** `responseType: 'code'` is safer than implicit flow. 3. **Validate tokens on your backend** Decode and verify issuer, audience, expiration, and signature server-side. 4. **Store refresh tokens securely** For native apps, pair this plugin with [@capgo/capacitor-persistent-account](https://github.com/Cap-go/capacitor-persistent-account). 5. **Use HTTPS everywhere** Production auth endpoints and logout endpoints should always use HTTPS. ## Troubleshooting [Section titled “Troubleshooting”](#troubleshooting) ### `providerId is required` [Section titled “providerId is required”](#providerid-is-required) Every OAuth2 method needs the configured provider key: ```typescript await SocialLogin.login({ provider: 'oauth2', options: { providerId: 'github' }, }); ``` ### `OAuth2 provider "xxx" not configured` [Section titled “OAuth2 provider "xxx" not configured”](#oauth2-provider-xxx-not-configured) Call `SocialLogin.initialize()` before login and make sure the `providerId` matches the object key under `oauth2`. ### Redirect URL mismatch [Section titled “Redirect URL mismatch”](#redirect-url-mismatch) * Compare the configured redirect URL in your app and provider dashboard character by character. * Watch for trailing slashes, scheme mismatches, and different hosts. * Make sure mobile app URL schemes are registered before testing on device. ### No refresh token returned [Section titled “No refresh token returned”](#no-refresh-token-returned) Most providers only return refresh tokens when you request scopes like `offline_access` or explicitly force consent. Review the provider-specific policy. ### Debugging token exchange [Section titled “Debugging token exchange”](#debugging-token-exchange) Enable `logsEnabled: true` on the provider config to inspect generated URLs and token exchange details. ## Related docs [Section titled “Related docs”](#related-docs) * [Social Login getting started](/docs/plugins/social-login/getting-started/) * [Ionic Auth Connect migration](/docs/plugins/social-login/migrations/ionic-auth-connect/) # Supabase Apple Login on Android > Learn how to set up Apple Sign-In with Supabase Authentication on Android using the Capacitor Social Login plugin. ## Prerequisites [Section titled “Prerequisites”](#prerequisites) This guide will help you integrate Apple Sign-In with Supabase Authentication on Android. It is assumed that you have already completed: * the [Supabase Apple Login - General Setup](../general/). Important Apple Sign-In on Android requires a backend server because Apple doesn’t provide native Android support. We’ll use a Supabase Edge Function as the backend. ## Step 1: Deploy the Backend Edge Function [Section titled “Step 1: Deploy the Backend Edge Function”](#step-1-deploy-the-backend-edge-function) First, we need to deploy the Supabase Edge Function that will handle the Apple OAuth callback. 1. **Navigate to your Supabase project directory** ```bash cd your-project/supabase ``` 2. **Create the edge function** (if it doesn’t exist) ```bash supabase functions new apple-signin-callback ``` 3. **Copy the edge function code** The complete edge function implementation is available in the [example app](https://github.com/Cap-go/capacitor-social-login/tree/main/example-app/supabase/functions/apple-signin-callback). Copy the following files to your project: * `supabase/functions/apple-signin-callback/index.ts` - Main edge function code * `supabase/functions/apple-signin-callback/deno.json` - Import map for dependencies (includes `jose` library for JWT signing) 4. **Configure JWT verification** The Apple OAuth callback endpoint must be public (no authentication required) because Apple will redirect to it. Update your `supabase/config.toml` file: ```toml [functions.apple-signin-callback] enabled = true verify_jwt = false # Important: Set to false for public OAuth callback import_map = "./functions/apple-signin-callback/deno.json" entrypoint = "./functions/apple-signin-callback/index.ts" ``` Important Setting `verify_jwt = false` makes this endpoint public. This is required because Apple’s OAuth redirect doesn’t include Supabase authentication headers. The endpoint validates the OAuth flow itself. 5. **Deploy the function** ```bash supabase functions deploy apple-signin-callback ``` 6. **Get your function URL** After deployment, you’ll get a URL like: ```plaintext https://your-project-ref.supabase.co/functions/v1/apple-signin-callback ``` If you cannot find it, you can do the following: 1. Open `https://supabase.com/dashboard/project/YOUR_PROJECT_REF/functions` 2. Click on the `apple-signin-callback` function URL to copy it. ![Supabase Functions Apple Sign-In Callback](/social-login-assets/supabase_functions_apple_signin_callback.webp) Save this URL You’ll need this URL in the next step when configuring Apple Developer Portal. ## Step 2: Configure Apple Developer Portal [Section titled “Step 2: Configure Apple Developer Portal”](#step-2-configure-apple-developer-portal) Now we need to configure Apple Developer Portal with the backend URL and get all the required values. Function URL Make sure you have your Supabase Edge Function URL from Step 1 before proceeding. You’ll need it to configure the Return URL in Apple Developer Portal. 1. **Follow the Apple Login Android Setup Guide** Complete the [Apple Login Android Setup guide](/docs/plugins/social-login/apple/android/) to: * Create a Service ID * Generate a private key (.p8 file) * Get your Team ID and Key ID * Configure the Return URL 2. **Set the Return URL in Apple Developer Portal** When configuring the Return URL in Apple Developer Portal (step 6.9 of the Apple guide), use your Supabase Edge Function URL: ```plaintext https://your-project-ref.supabase.co/functions/v1/apple-signin-callback ``` Important: Use Supabase Edge Function URL **Do NOT** use the redirect URL from the [Apple Login Android Setup guide](/docs/plugins/social-login/apple/android/). That guide uses a custom backend server URL. For Supabase integration, you **must** use your Supabase Edge Function URL instead. Exact Match Required The Return URL must match **exactly** what you configure here. Apple is very strict about redirect URI matching. 3. **Collect all required values** After completing the Apple setup guide, you should have: * **APPLE\_TEAM\_ID**: Your Apple Developer Team ID * **APPLE\_KEY\_ID**: The Key ID from Apple Developer Portal * **APPLE\_PRIVATE\_KEY**: Your .p8 private key file (needs to be base64 encoded) * **ANDROID\_SERVICE\_ID**: Your Apple Service ID (e.g., `com.example.app.service`) * **BASE\_REDIRECT\_URL**: Your deep link URL (e.g., `capgo-demo-app://path`) Deep Link URL The `BASE_REDIRECT_URL` is the deep link scheme configured in your `AndroidManifest.xml`. This is where the backend will redirect after authentication. The value of your deep link is dependent on the `android:scheme="capgo-demo-app"` code. If you have set `android:scheme="capgo-demo-app"` in your `AndroidManifest.xml`, then your deep link will be `capgo-demo-app://path`. ## Step 3: Set Supabase Secrets [Section titled “Step 3: Set Supabase Secrets”](#step-3-set-supabase-secrets) Now we need to configure the environment variables (secrets) for the Supabase Edge Function. 1. **Encode your private key** First, encode your Apple private key (.p8 file) to base64: ```bash base64 -i AuthKey_XXXXX.p8 ``` Copy the entire output (it’s a single long string). 2. **Set secrets using Supabase CLI** ```bash supabase secrets set APPLE_TEAM_ID=your_team_id supabase secrets set APPLE_KEY_ID=your_key_id supabase secrets set APPLE_PRIVATE_KEY=your_base64_encoded_key supabase secrets set ANDROID_SERVICE_ID=your.service.id supabase secrets set BASE_REDIRECT_URL=your-app://path supabase secrets set APPLE_REDIRECT_URI=https://your-project-ref.supabase.co/functions/v1/apple-signin-callback ``` Replace Placeholders Replace all the placeholder values with your actual values from Step 2. 3. **Alternative: Set secrets in Supabase Dashboard** If you prefer using the dashboard: 1. Go to your Supabase project dashboard 2. Navigate to **Edge Functions** → **Settings** → **Secrets** 3. Add each secret variable with its value Android App Configuration The [Apple Login Android Setup guide](/docs/plugins/social-login/apple/android/) already covers configuring your Android app: * Adding the deep link intent filter to `AndroidManifest.xml` * Adding the `onNewIntent` handler to `MainActivity.java` Make sure you’ve completed those steps before proceeding. The deep link scheme you configure there will be your `BASE_REDIRECT_URL` in Step 3. ## Step 4: Use the Authentication Helper [Section titled “Step 4: Use the Authentication Helper”](#step-4-use-the-authentication-helper) Now you can use the authentication helper in your app code. ### Implementation [Section titled “Implementation”](#implementation) The complete implementation is available in the [example app’s `supabaseAuthUtils.ts`](https://github.com/Cap-go/capacitor-social-login/blob/main/example-app/src/supabaseAuthUtils.ts) file. ### Using the Authentication Helper [Section titled “Using the Authentication Helper”](#using-the-authentication-helper) ```typescript import { authenticateWithAppleSupabase } from './supabaseAuthUtils'; const result = await authenticateWithAppleSupabase(); if (result.success) { console.log('Signed in:', result.user); // Navigate to your authenticated area } else { console.error('Error:', result.error); } ``` ### Update the Helper Function [Section titled “Update the Helper Function”](#update-the-helper-function) When using the `authenticateWithAppleSupabase` helper function, you **must** update the following values to match your configuration: 1. **Update `redirectUrl`** - Set this to your Supabase Edge Function URL: ```typescript const redirectUrl = platform === 'android' ? 'https://your-project-ref.supabase.co/functions/v1/apple-signin-callback' : undefined; ``` 2. **Update `clientId`** - Set this to your Apple Service ID: ```typescript await SocialLogin.initialize({ apple: { clientId: isIOS ? undefined // iOS uses bundle ID automatically : 'your.service.id.here', // Your Apple Service ID for Android redirectUrl: redirectUrl, }, }); ``` Important Replace `'your.service.id.here'` with your actual Apple Service ID (the same value you used for `ANDROID_SERVICE_ID` in Step 3). See the [complete implementation](https://github.com/Cap-go/capacitor-social-login/blob/main/example-app/src/supabaseAuthUtils.ts) for reference. ## Step 5: Test the Integration [Section titled “Step 5: Test the Integration”](#step-5-test-the-integration) 1. **Build and run your Android app** ```bash npx cap sync android npx cap run android ``` 2. **Test the authentication flow** * Tap the “Sign in with Apple” button * You should see the Apple OAuth page in a browser * After authenticating, you should be redirected back to your app * Check the console logs for any errors 3. **Verify the flow** The complete flow should be: 1. User taps “Sign in with Apple” 2. App opens browser with Apple OAuth 3. User authenticates with Apple 4. Apple redirects to: `https://your-project-ref.supabase.co/functions/v1/apple-signin-callback` 5. Edge function exchanges code for tokens 6. Edge function redirects to: `your-app://path?id_token=...&access_token=...` 7. Android app receives the deep link and processes the identity token 8. App signs in to Supabase with the identity token ## Troubleshooting [Section titled “Troubleshooting”](#troubleshooting) If authentication fails: * **Redirect URI mismatch**: Verify the Return URL in Apple Developer Portal matches exactly with `APPLE_REDIRECT_URI` secret * **Deep link not working**: Check that `AndroidManifest.xml` intent filter matches your `BASE_REDIRECT_URL` * **Missing secrets**: Verify all secrets are set correctly using `supabase secrets list` * **Token exchange fails**: Check edge function logs in Supabase Dashboard for detailed error messages * **App doesn’t receive callback**: Ensure `onNewIntent` is properly implemented in MainActivity * Review the [example app code](https://github.com/Cap-go/capacitor-social-login/blob/main/example-app/src/supabaseAuthUtils.ts) for reference ## How It Works [Section titled “How It Works”](#how-it-works) On Android, Apple Sign-In uses an OAuth redirect flow: 1. **Initialization**: The plugin is initialized with your Service ID and backend redirect URL 2. **OAuth Flow**: Opens a browser/Chrome Custom Tab with Apple’s OAuth page 3. **Backend Callback**: Apple redirects to your Supabase Edge Function with an authorization code 4. **Token Exchange**: The edge function exchanges the code for tokens using Apple’s token endpoint 5. **Deep Link Redirect**: The edge function redirects back to your app with the identity token 6. **Supabase Authentication**: The app receives the token and signs in to Supabase This flow is necessary because Apple doesn’t provide native Android support for Sign in with Apple. # Supabase Apple Login - General Setup > Learn how to integrate Apple Sign-In with Supabase Authentication using the Capacitor Social Login plugin. ## Overview [Section titled “Overview”](#overview) This guide will help you integrate Apple Sign-In with Supabase Authentication. Apple Sign-In provides a secure, privacy-focused authentication method that works across iOS, Android, and Web platforms. ## Prerequisites [Section titled “Prerequisites”](#prerequisites) Before starting, ensure you have: 1. [Created a Supabase project](https://database.new/) 2. Read the [Apple Login General Setup](/docs/plugins/social-login/apple/general/) guide to setup Apple OAuth credentials 3. Followed the respective platform-specific guides to setup Apple OAuth credentials for your target platform: * [Android Setup](/docs/plugins/social-login/apple/android/) * [iOS Setup](/docs/plugins/social-login/apple/ios/) * [Web Setup](/docs/plugins/social-login/apple/web/) Note Before starting the Supabase tutorial, you need to generate the client IDs for the platforms you plan to use. For iOS, the client ID is the same as your app ID. For Android and Web, the client ID is the same as your service ID. You will use them in step 7 of this guide. ## Enabling Apple OAuth provider in Supabase [Section titled “Enabling Apple OAuth provider in Supabase”](#enabling-apple-oauth-provider-in-supabase) 1. Go to your [Supabase Dashboard](https://app.supabase.com/) 2. Click on your project ![Supabase Project Selector](/social-login-assets/supabase_project_select.webp) 3. Do go to the `Authentication` menu ![Supabase Authentication Menu](/social-login-assets/supabase_authentication_menu.webp) 4. Click on the `Providers` tab ![Supabase Providers Tab](/social-login-assets/supabase_providers_tab.webp) 5. Find the `Apple` provider ![Supabase Apple Provider](/social-login-assets/supabase_apple_provider.webp) 6. Enable the `Apple` provider ![Supabase Apple Provider Enable](/social-login-assets/supabase_apple_provider_enable.webp) 7. Fill in the client ID configuration: Note If you are using Apple login for iOS, the client ID is the same as your app ID. If you are using Apple login for Android or Web, the client ID is the same as your service ID. If you are using both, you need to provide both the app ID and the service ID. ![Supabase Apple Provider Client ID](/social-login-assets/supabase_apple_provider_client_id.webp) 8. Click on the `Save` button ![Supabase Apple Provider Save](/social-login-assets/supabase_apple_provider_save.webp) Note You ****DO NOT HAVE TO**** setup `Secret key (for OAuth)`. We will do a custom backend implementation to handle the Apple login. Voilà, you have now enabled Apple Sign-In with Supabase Authentication 🎉 ## Using the Authentication Helper [Section titled “Using the Authentication Helper”](#using-the-authentication-helper) The complete implementation includes a helper function `authenticateWithAppleSupabase()` that handles the entire Apple Sign-In flow with Supabase. This function: * Initializes Apple Sign-In with platform-specific configuration * Handles the authentication flow (native on iOS, OAuth redirect on Android/Web) * Extracts the identity token from Apple * Signs in to Supabase with the identity token Complete Implementation The complete implementation is available in the [example app’s `supabaseAuthUtils.ts`](https://github.com/Cap-go/capacitor-social-login/blob/main/example-app/src/supabaseAuthUtils.ts) file. ### Basic Usage [Section titled “Basic Usage”](#basic-usage) ```typescript import { authenticateWithAppleSupabase } from './supabaseAuthUtils'; const result = await authenticateWithAppleSupabase(); if (result.success) { console.log('Signed in:', result.user); // Navigate to your authenticated area } else { console.error('Error:', result.error); } ``` ### How It Works [Section titled “How It Works”](#how-it-works) The helper function automatically handles platform-specific differences: * **iOS**: Uses native Apple Sign-In (no redirect URL needed, uses bundle ID automatically) * **Android**: Uses OAuth redirect flow with backend edge function (requires Service ID) * **Web**: Uses OAuth popup flow (requires Service ID and current page URL as redirect) The function returns an identity token from Apple, which is then used to authenticate with Supabase using `supabase.auth.signInWithIdToken()`. # Supabase Apple Login on iOS Setup > Learn how to integrate Apple Sign-In with Supabase Authentication on iOS. ## Prerequisites [Section titled “Prerequisites”](#prerequisites) This guide will help you integrate Apple Sign-In with Supabase Authentication on iOS. It is assumed that you have already completed: * the [Apple Login iOS setup](/docs/plugins/social-login/apple/ios/) * the [Supabase Apple Login - General Setup](../general/). ## Implementation [Section titled “Implementation”](#implementation) The complete implementation is available in the [example app’s `supabaseAuthUtils.ts`](https://github.com/Cap-go/capacitor-social-login/blob/main/example-app/src/supabaseAuthUtils.ts) file. This guide explains the key concepts and how to use it. ### Using the Authentication Helper [Section titled “Using the Authentication Helper”](#using-the-authentication-helper) The `authenticateWithAppleSupabase` function handles the entire authentication flow: ```typescript import { authenticateWithAppleSupabase } from './supabaseAuthUtils'; const result = await authenticateWithAppleSupabase(); if (result.success) { console.log('Signed in:', result.user); // Navigate to your authenticated area } else { console.error('Error:', result.error); } ``` ## How It Works [Section titled “How It Works”](#how-it-works) On iOS, Apple Sign-In uses the native implementation: 1. **Initialization**: The plugin uses your app’s bundle ID automatically (no `clientId` needed) 2. **Native Sign-In**: Uses Apple’s native Sign in with Apple button and authentication flow 3. **Identity Token**: Apple returns an identity token (JWT) containing user information 4. **Supabase Authentication**: The identity token is sent to Supabase using `signInWithIdToken()` The helper function automatically detects the iOS platform and configures everything appropriately. ## Important Notes [Section titled “Important Notes”](#important-notes) ### Bundle ID Configuration [Section titled “Bundle ID Configuration”](#bundle-id-configuration) * iOS uses your app’s bundle ID automatically for Apple Sign-In * Make sure your bundle ID matches what’s configured in Apple Developer Portal * The bundle ID should have “Sign in with Apple” capability enabled ### Supabase Client ID [Section titled “Supabase Client ID”](#supabase-client-id) In Supabase, configure your Apple provider with: * **Client ID**: Your iOS App ID (bundle ID) - e.g., `app.capgo.plugin.SocialLogin` If you’re also using Android/Web, you’ll need to provide both the App ID and Service ID in Supabase’s Client ID field (comma-separated). ## Troubleshooting [Section titled “Troubleshooting”](#troubleshooting) If authentication fails: * **Bundle ID mismatch**: Verify your bundle ID matches in both Xcode and Apple Developer Portal * **Capability not enabled**: Ensure “Sign in with Apple” capability is enabled in Xcode * **Supabase configuration**: Verify your App ID is correctly configured in Supabase Apple provider settings * **Token validation fails**: Check that the identity token is being received from Apple * Review the [example app code](https://github.com/Cap-go/capacitor-social-login/blob/main/example-app/src/supabaseAuthUtils.ts) for reference # Supabase Apple Login on Web > Learn how to integrate Apple Sign-In with Supabase Authentication on Web. ## Prerequisites [Section titled “Prerequisites”](#prerequisites) This guide will help you integrate Apple Sign-In with Supabase Authentication on Web. It is assumed that you have already completed: * the [Apple Login Web setup](/docs/plugins/social-login/apple/web/) * the [Supabase Apple Login - General Setup](../general/). ## Implementation [Section titled “Implementation”](#implementation) The complete implementation is available in the [example app’s `supabaseAuthUtils.ts`](https://github.com/Cap-go/capacitor-social-login/blob/main/example-app/src/supabaseAuthUtils.ts) file. This guide explains the key concepts and how to use it. ### Using the Authentication Helper [Section titled “Using the Authentication Helper”](#using-the-authentication-helper) The `authenticateWithAppleSupabase` function handles the entire authentication flow: ```typescript import { authenticateWithAppleSupabase } from './supabaseAuthUtils'; const result = await authenticateWithAppleSupabase(); if (result.success) { console.log('Signed in:', result.user); // Navigate to your authenticated area } else { console.error('Error:', result.error); } ``` ## How It Works [Section titled “How It Works”](#how-it-works) On Web, Apple Sign-In uses an OAuth popup flow: 1. **Initialization**: The plugin is initialized with your Service ID and the current page URL as the redirect URL 2. **OAuth Popup**: Opens a popup window with Apple’s OAuth page 3. **User Authentication**: User authenticates with Apple in the popup 4. **Identity Token**: Apple returns an identity token (JWT) containing user information 5. **Supabase Authentication**: The identity token is sent to Supabase using `signInWithIdToken()` The helper function automatically detects the web platform and configures everything appropriately. ## Important Notes [Section titled “Important Notes”](#important-notes) ### Service ID Configuration [Section titled “Service ID Configuration”](#service-id-configuration) * Web requires your Apple Service ID (same as Android) * The Service ID must be configured in Apple Developer Portal with the correct Return URLs * Make sure your domain is added to the allowed domains in Apple Developer Portal ### Redirect URL [Section titled “Redirect URL”](#redirect-url) * On web, the redirect URL is automatically set to `window.location.href` (current page URL) * This must match one of the Return URLs configured in Apple Developer Portal * Ensure both the URL with and without trailing slash are configured in Apple Developer Portal ### Supabase Client ID [Section titled “Supabase Client ID”](#supabase-client-id) In Supabase, configure your Apple provider with: * **Client ID**: Your Apple Service ID (e.g., `com.example.app.service`) If you’re also using iOS, you’ll need to provide both the App ID and Service ID in Supabase’s Client ID field (comma-separated). ### Update the Helper Function [Section titled “Update the Helper Function”](#update-the-helper-function) When using the `authenticateWithAppleSupabase` helper function, you **must** update the `clientId` to match your Apple Service ID: ```typescript await SocialLogin.initialize({ apple: { clientId: isIOS ? undefined // iOS uses bundle ID automatically : 'your.service.id.here', // Your Apple Service ID for Web and Android redirectUrl: redirectUrl, }, }); ``` Important Replace `'your.service.id.here'` with your actual Apple Service ID (the same value you configured in Apple Developer Portal). ## Troubleshooting [Section titled “Troubleshooting”](#troubleshooting) If authentication fails: * **Service ID mismatch**: Verify your Service ID matches in both Apple Developer Portal and your code * **Return URL not configured**: Ensure your current page URL (with and without trailing slash) is configured in Apple Developer Portal * **Popup blocked**: Check browser settings - some browsers block popups by default * **Domain not allowed**: Verify your domain is added to the allowed domains in Apple Developer Portal * **Supabase configuration**: Verify your Service ID is correctly configured in Supabase Apple provider settings * Review the [example app code](https://github.com/Cap-go/capacitor-social-login/blob/main/example-app/src/supabaseAuthUtils.ts) for reference # Supabase Google Login on Android > Learn how to set up Google Sign-In with Supabase Authentication on Android using the Capacitor Social Login plugin. ## Introduction [Section titled “Introduction”](#introduction) This guide will help you integrate Google Sign-In with Supabase Authentication on Android. It is assumed that you have already completed: * the [Google Login Android setup](/docs/plugins/social-login/google/android/) * the [Supabase Google Login - General Setup](/docs/plugins/social-login/supabase/google/general/). ## Implementation [Section titled “Implementation”](#implementation) The complete implementation is available in the [example app’s `supabaseAuthUtils.ts`](https://github.com/Cap-go/capacitor-social-login/blob/main/example-app/src/supabaseAuthUtils.ts) file. This guide explains the key concepts and how to use it. ### Using the Authentication Helper [Section titled “Using the Authentication Helper”](#using-the-authentication-helper) The `authenticateWithGoogleSupabase` function handles the entire authentication flow: ```typescript import { authenticateWithGoogleSupabase } from './supabaseAuthUtils'; const result = await authenticateWithGoogleSupabase(); if (result.success) { console.log('Signed in:', result.user); // Navigate to your authenticated area } else { console.error('Error:', result.error); } ``` ## How It Works [Section titled “How It Works”](#how-it-works) For a detailed explanation of how the authentication flow works, including nonce generation, JWT validation, and Supabase sign-in, see the [How It Works section in the General Setup guide](/docs/plugins/social-login/supabase/google/general/#how-it-works). For the complete code reference, see the [Complete Code Reference section in the General Setup guide](/docs/plugins/social-login/supabase/google/general/#complete-code-reference). ## Important Notes [Section titled “Important Notes”](#important-notes) ### Nonce Handling [Section titled “Nonce Handling”](#nonce-handling) The nonce implementation follows the pattern from the [React Native Google Sign In documentation](https://react-native-google-signin.github.io/docs/security#usage-with-supabase): * `rawNonce` goes to Supabase’s `signInWithIdToken()` * Supabase makes a hash of `rawNonce` and compares it with the `nonceDigest` which is included in the ID token from Google Sign-In * `nonceDigest` (SHA-256 hash, hex-encoded) goes to the `nonce` parameter in Google Sign-In APIs ### Automatic Retry [Section titled “Automatic Retry”](#automatic-retry) The implementation includes automatic retry logic: * If JWT validation fails on first attempt, it logs out and retries once * This handles cases where cached tokens might have incorrect nonces * If the retry also fails, an error is returned ## Troubleshooting [Section titled “Troubleshooting”](#troubleshooting) If authentication fails: * **Invalid audience**: Verify your Google Client IDs match in both Google Cloud Console and Supabase * **Nonce mismatch**: Check console logs - the function will automatically retry, but you can manually logout first if needed * **Token validation fails**: Ensure you’re using `mode: 'online'` in the initialize call to get an idToken * Review the [example app code](https://github.com/Cap-go/capacitor-social-login/blob/main/example-app/src/supabaseAuthUtils.ts) for reference # Supabase Google Login - General Setup > Learn how to set up Google Sign-In with Supabase Authentication using the Capacitor Social Login plugin. ## Introduction [Section titled “Introduction”](#introduction) This guide will walk you through integrating Google Sign-In with Supabase Authentication using the Capacitor Social Login plugin. This setup allows you to use native Google Sign-In on mobile platforms while leveraging Supabase Auth for backend authentication. ## Prerequisites [Section titled “Prerequisites”](#prerequisites) Before starting, ensure you have: 1. [Created a Supabase project](https://database.new/) 2. Read the [Google Login General Setup](/docs/plugins/social-login/google/general/) guide to setup Google OAuth credentials 3. Followed the respective platform-specific guides to setup Google OAuth credentials for your target platform: * [Android Setup](/docs/plugins/social-login/google/android/) * [iOS Setup](/docs/plugins/social-login/google/ios/) * [Web Setup](/docs/plugins/social-login/google/web/) Note Before starting the Supabase tutorial, you need to generate the client IDs for the platforms you plan to use. You will use them in step 7 of this guide. ## Enabling Google OAuth provider in Supabase [Section titled “Enabling Google OAuth provider in Supabase”](#enabling-google-oauth-provider-in-supabase) 1. Go to your [Supabase Dashboard](https://app.supabase.com/) 2. Click on your project ![Supabase Project Selector](/social-login-assets/supabase_project_select.webp) 3. Do go to the `Authentication` menu ![Supabase Authentication Menu](/social-login-assets/supabase_authentication_menu.webp) 4. Click on the `Providers` tab ![Supabase Providers Tab](/social-login-assets/supabase_providers_tab.webp) 5. Find the `Google` provider ![Supabase Google Provider](/social-login-assets/supabase_google_provider.webp) 6. Enable the provider ![Supabase Google Provider Enable](/social-login-assets/supabase_google_provider_enable.webp) 7. Add the client IDs for the platforms you plan to use ![Supabase Google Provider Add Client IDs](/social-login-assets/supabase_google_provider_add_client_ids.webp) Note This included the web client ID, the iOS client ID and the Android client ID. You can skip providing some of them, depending on the platforms you plan to use. 8. Click on the `Save` button ![Supabase Google Provider Save](/social-login-assets/supabase_google_provider_save.webp) Note You ****SHOULD NOT**** setup `Client Secret (for OAuth)` or `Callback URL (for OAuth)`. Some sources might also suggest setting `Skip nonce checks` for Google on iOS, but with this guide this isn’t needed. Voilà, you have now enabled Google Sign-In with Supabase Authentication 🎉 ## How Google Sign-In with Supabase Authentication Helper Works [Section titled “How Google Sign-In with Supabase Authentication Helper Works”](#how-google-sign-in-with-supabase-authentication-helper-works) This section explains how the Google Sign-In integration with Supabase works under the hood. Understanding this flow will help you implement and troubleshoot the authentication process. Complete Implementation The complete implementation is available in the [example app’s `supabaseAuthUtils.ts`](https://github.com/Cap-go/capacitor-social-login/blob/main/example-app/src/supabaseAuthUtils.ts) file. ### 1. Nonce Generation [Section titled “1. Nonce Generation”](#1-nonce-generation) The implementation generates a secure nonce pair following the [Supabase nonce requirements](https://react-native-google-signin.github.io/docs/security#usage-with-supabase): ```typescript // Generate URL-safe random nonce function getUrlSafeNonce(): string { const array = new Uint8Array(32); crypto.getRandomValues(array); return Array.from(array, (byte) => byte.toString(16).padStart(2, '0')).join(''); } // Hash the nonce with SHA-256 async function sha256Hash(message: string): Promise<string> { const encoder = new TextEncoder(); const data = encoder.encode(message); const hashBuffer = await crypto.subtle.digest('SHA-256', data); const hashArray = Array.from(new Uint8Array(hashBuffer)); return hashArray.map((b) => b.toString(16).padStart(2, '0')).join(''); } // Generate nonce pair async function getNonce(): Promise<{ rawNonce: string; nonceDigest: string }> { const rawNonce = getUrlSafeNonce(); const nonceDigest = await sha256Hash(rawNonce); return { rawNonce, nonceDigest }; } ``` **Flow:** * `rawNonce`: URL-safe random string (64 hex characters) * `nonceDigest`: SHA-256 hash of `rawNonce` (hex-encoded) * `nonceDigest` is passed to Google Sign-In → Google includes the nonce digest in the ID token * `rawNonce` is passed to Supabase → Supabase hashes the raw nonce and compares with the token’s nonce ### 2. Google Sign-In [Section titled “2. Google Sign-In”](#2-google-sign-in) The function initializes the plugin and signs in with Google: ```typescript await SocialLogin.initialize({ google: { webClientId: 'YOUR_WEB_CLIENT_ID.apps.googleusercontent.com', // iOS only: iOSClientId: 'YOUR_IOS_CLIENT_ID.apps.googleusercontent.com', mode: 'online', // Required to get idToken }, }); const response = await SocialLogin.login({ provider: 'google', options: { scopes: ['email', 'profile'], nonce: nonceDigest, // Pass the SHA-256 hashed nonce }, }); ``` ### 3. JWT Validation [Section titled “3. JWT Validation”](#3-jwt-validation) Before sending the token to Supabase, the implementation validates the JWT token: ```typescript function validateJWTToken(idToken: string, expectedNonceDigest: string): { valid: boolean; error?: string } { const decodedToken = decodeJWT(idToken); // Check audience matches your Google Client IDs const audience = decodedToken.aud; if (!VALID_GOOGLE_CLIENT_IDS.includes(audience)) { return { valid: false, error: 'Invalid audience' }; } // Check nonce matches const tokenNonce = decodedToken.nonce; if (tokenNonce && tokenNonce !== expectedNonceDigest) { return { valid: false, error: 'Nonce mismatch' }; } return { valid: true }; } ``` **Why validate before Supabase?** Validating the JWT token before sending the token to Supabase serves several important purposes: 1. **Prevent Invalid Requests**: If the token has an incorrect audience or nonce mismatch, Supabase will reject the token anyway. Validating first avoids unnecessary API calls and provides clearer error messages. 2. **Token Caching Issues**: On some platforms (especially iOS), Google Sign-In SDK can cache tokens for performance. When a cached token is returned, the cached token may have been generated with a different nonce (or no nonce at all), causing Supabase to reject the token with a “nonce mismatch” error. By validating before sending to Supabase, we can detect this issue early and automatically retry with a fresh token. 3. **Security** (iOS): On iOS, validation ensures the token was issued for your specific Google Client IDs, preventing potential security issues from using tokens intended for other applications. 4. **Better Error Handling**: Detecting issues before Supabase allows for automatic retry logic, which is essential for handling iOS caching issues transparently. If validation fails, the function automatically: 1. Logs out from Google (clears cached tokens - critical on iOS) 2. Retries authentication once (forces fresh token generation with correct nonce) 3. If retry also fails, returns an error ### 4. Supabase Sign-In [Section titled “4. Supabase Sign-In”](#4-supabase-sign-in) Finally, the validated token is sent to Supabase: ```typescript const { data, error } = await supabase.auth.signInWithIdToken({ provider: 'google', token: googleResponse.idToken, nonce: rawNonce, // Pass the raw (unhashed) nonce }); ``` ## Complete Code Reference [Section titled “Complete Code Reference”](#complete-code-reference) The complete implementation is available in the [example app’s `supabaseAuthUtils.ts`](https://github.com/Cap-go/capacitor-social-login/blob/main/example-app/src/supabaseAuthUtils.ts) file, which includes: * `getUrlSafeNonce()` - Generates URL-safe random nonce * `sha256Hash()` - Hashes string with SHA-256 * `getNonce()` - Generates nonce pair * `decodeJWT()` - Decodes JWT token * `validateJWTToken()` - Validates JWT audience and nonce * `authenticateWithGoogleSupabase()` - Main authentication function with automatic retry ### Additional Example Files [Section titled “Additional Example Files”](#additional-example-files) * [SupabasePage.tsx](https://github.com/Cap-go/capacitor-social-login/blob/main/example-app/src/SupabasePage.tsx) - Example component with redirect handling (Web) * [SupabaseCreateAccountPage.tsx](https://github.com/Cap-go/capacitor-social-login/blob/main/example-app/src/SupabaseCreateAccountPage.tsx) - Example create account page ## Next Steps [Section titled “Next Steps”](#next-steps) Please proceed to the platform-specific setup guide for your target platform: * [Android Setup](../android/) * [iOS Setup](../ios/) * [Web Setup](../web/) # Supabase Google Login on iOS > Learn how to set up Google Sign-In with Supabase Authentication on iOS using the Capacitor Social Login plugin. ## Introduction [Section titled “Introduction”](#introduction) This guide will help you integrate Google Sign-In with Supabase Authentication on iOS. It is assumed that you have already completed: * the [Google Login iOS setup](/docs/plugins/social-login/google/ios/) * the [Supabase Google Login - General Setup](/docs/plugins/social-login/supabase/google/general/). ## Implementation [Section titled “Implementation”](#implementation) The complete implementation is available in the [example app’s `supabaseAuthUtils.ts`](https://github.com/Cap-go/capacitor-social-login/blob/main/example-app/src/supabaseAuthUtils.ts) file. This guide explains the key concepts and how to use it. ### Using the Authentication Helper [Section titled “Using the Authentication Helper”](#using-the-authentication-helper) The `authenticateWithGoogleSupabase` function handles the entire authentication flow: ```typescript import { authenticateWithGoogleSupabase } from './supabaseAuthUtils'; const result = await authenticateWithGoogleSupabase(); if (result.success) { console.log('Signed in:', result.user); // Navigate to your authenticated area } else { console.error('Error:', result.error); } ``` ## How It Works [Section titled “How It Works”](#how-it-works) For a detailed explanation of how the authentication flow works, including nonce generation, JWT validation, and Supabase sign-in, see the [How It Works section in the General Setup guide](/docs/plugins/social-login/supabase/google/general/#how-it-works). ## Important Caveats [Section titled “Important Caveats”](#important-caveats) ### iOS Token Caching and Nonce Issues [Section titled “iOS Token Caching and Nonce Issues”](#ios-token-caching-and-nonce-issues) iOS Nonce Caching Issue On iOS, Google Sign-In can cache tokens, which may cause the nonce validation to fail. The `validateJWTToken` function detects this and automatically handles it: 1. **Automatic Detection**: The function checks if the nonce in the token matches the expected `nonceDigest` 2. **Automatic Retry**: If validation fails, it automatically logs out from Google and retries once 3. **Error Handling**: If the retry also fails, an error is returned **Why this happens**: iOS Google Sign-In SDK caches tokens for performance. When a cached token is returned, it may have been generated with a different nonce (or no nonce), causing a mismatch. **The solution**: The implementation automatically handles this by logging out and retrying, which forces Google to generate a fresh token with the correct nonce. **Manual Workaround** (if automatic retry doesn’t work): ```typescript // Logout first to clear cached tokens await SocialLogin.logout({ provider: 'google' }); // Then authenticate const result = await authenticateWithGoogleSupabase(); ``` This ensures a fresh token is obtained with the correct nonce. For the complete code reference, see the [Complete Code Reference section in the General Setup guide](/docs/plugins/social-login/supabase/google/general/#complete-code-reference). ## Important Notes [Section titled “Important Notes”](#important-notes) ### Nonce Handling [Section titled “Nonce Handling”](#nonce-handling) The nonce implementation follows the pattern from the [React Native Google Sign In documentation](https://react-native-google-signin.github.io/docs/security#usage-with-supabase): * `rawNonce` goes to Supabase’s `signInWithIdToken()` * Supabase makes a hash of `rawNonce` and compares it with the `nonceDigest` which is included in the ID token from Google Sign-In * `nonceDigest` (SHA-256 hash, hex-encoded) goes to the `nonce` parameter in Google Sign-In APIs ### Automatic Retry Mechanism [Section titled “Automatic Retry Mechanism”](#automatic-retry-mechanism) The `authenticateWithGoogleSupabase` function includes a `retry` parameter: * First call (`retry=false`): If validation fails, automatically logs out and retries once * Retry call (`retry=true`): If validation fails again, immediately returns an error This handles the iOS token caching issue automatically. ## Troubleshooting [Section titled “Troubleshooting”](#troubleshooting) If authentication fails: * **Nonce mismatch**: The function automatically retries - check console logs for details. If it persists, manually logout first * **Invalid audience**: Verify your Google Client IDs match in both Google Cloud Console and Supabase (both iOS and Web client IDs) * **Token validation fails**: Ensure you’re using `mode: 'online'` in the initialize call to get an idToken * **Info.plist configuration**: Ensure Info.plist has the correct URL schemes and GIDClientID * Review the [example app code](https://github.com/Cap-go/capacitor-social-login/blob/main/example-app/src/supabaseAuthUtils.ts) for reference # Supabase Google Login on Web > Learn how to set up Google Sign-In with Supabase Authentication on Web using the Capacitor Social Login plugin. ## Introduction [Section titled “Introduction”](#introduction) This guide will help you integrate Google Sign-In with Supabase Authentication on Web. It is assumed that you have already completed: * the [Google Login Web setup](/docs/plugins/social-login/google/web/) * the [Supabase Google Login - General Setup](/docs/plugins/social-login/supabase/google/general/). ## Implementation [Section titled “Implementation”](#implementation) The complete implementation is available in the [example app’s `supabaseAuthUtils.ts`](https://github.com/Cap-go/capacitor-social-login/blob/main/example-app/src/supabaseAuthUtils.ts) file. This guide explains the key concepts and how to use it. ### Using the Authentication Helper [Section titled “Using the Authentication Helper”](#using-the-authentication-helper) The `authenticateWithGoogleSupabase` function handles the entire authentication flow: ```typescript import { authenticateWithGoogleSupabase } from './supabaseAuthUtils'; const result = await authenticateWithGoogleSupabase(); if (result.success) { console.log('Signed in:', result.user); // Navigate to your authenticated area } else { console.error('Error:', result.error); } ``` ## Critical: Redirect Handling [Section titled “Critical: Redirect Handling”](#critical-redirect-handling) Critical: Redirect Handling When using Google login on web, you **MUST** call any function from the plugin when the redirect happens to initialize the plugin so it can handle the redirect and close the popup window. You can call either `isLoggedIn()` OR `initialize()` - both will trigger the redirect handling. This is essential for the OAuth popup flow to work correctly. ### Implementation Example [Section titled “Implementation Example”](#implementation-example) Add this to your component that handles Google Sign-In: ```typescript import { useEffect } from 'react'; import { SocialLogin } from '@capgo/capacitor-social-login'; function SupabasePage() { // Check Google login status on mount to invoke redirect handling // This doesn't serve any functional purpose in the UI but ensures // that any pending OAuth redirects are properly processed useEffect(() => { const checkGoogleLoginStatus = async () => { try { await SocialLogin.isLoggedIn({ provider: 'google' }); // We don't use the result, this is just to trigger redirect handling } catch (error) { // Ignore errors - this is just for redirect handling console.log('Google login status check completed (redirect handling)'); } }; checkGoogleLoginStatus(); }, []); // ... rest of your component } ``` See the [SupabasePage.tsx](https://github.com/Cap-go/capacitor-social-login/blob/main/example-app/src/SupabasePage.tsx) for a complete example. ## How It Works [Section titled “How It Works”](#how-it-works) For a detailed explanation of how the authentication flow works, including nonce generation, JWT validation, and Supabase sign-in, see the [How It Works section in the General Setup guide](/docs/plugins/social-login/supabase/google/general/#how-it-works). For the complete code reference, see the [Complete Code Reference section in the General Setup guide](/docs/plugins/social-login/supabase/google/general/#complete-code-reference). Also see: * [SupabasePage.tsx](https://github.com/Cap-go/capacitor-social-login/blob/main/example-app/src/SupabasePage.tsx) - Example component with redirect handling * [SupabaseCreateAccountPage.tsx](https://github.com/Cap-go/capacitor-social-login/blob/main/example-app/src/SupabaseCreateAccountPage.tsx) - Example create account page ## Important Notes [Section titled “Important Notes”](#important-notes) ### Redirect Handling [Section titled “Redirect Handling”](#redirect-handling) When using Google login on web, you **MUST** call any function from the plugin when the redirect happens to initialize the plugin so it can handle the redirect and close the popup window. You can call either `isLoggedIn()` OR `initialize()` - both will trigger the redirect handling. This is essential for the OAuth popup flow to work correctly. Without this, the popup window won’t close after authentication. ### Nonce Handling [Section titled “Nonce Handling”](#nonce-handling) The nonce implementation follows the pattern from the [React Native Google Sign In documentation](https://react-native-google-signin.github.io/docs/security#usage-with-supabase): * `rawNonce` goes to Supabase’s `signInWithIdToken()` * Supabase makes a hash of `rawNonce` and compares it with the `nonceDigest` which is included in the ID token from Google Sign-In * `nonceDigest` (SHA-256 hash, hex-encoded) goes to the `nonce` parameter in Google Sign-In APIs ### Automatic Retry [Section titled “Automatic Retry”](#automatic-retry) The implementation includes automatic retry logic: * If JWT validation fails on first attempt, it logs out and retries once * This handles cases where cached tokens might have incorrect nonces * If the retry also fails, an error is returned ## Troubleshooting [Section titled “Troubleshooting”](#troubleshooting) If authentication fails: * **Redirect not working**: Ensure you’re calling `isLoggedIn()` on component mount (see example above) * **Invalid audience**: Verify your Google Client IDs match in both Google Cloud Console and Supabase * **Authorized redirect URLs**: Check that authorized redirect URLs are configured in both Google Cloud Console and Supabase * **Nonce mismatch**: Check console logs - the function will automatically retry, but you can manually logout first if needed * **Token validation fails**: Ensure you’re using `mode: 'online'` in the initialize call to get an idToken * Review the [example app code](https://github.com/Cap-go/capacitor-social-login/blob/main/example-app/src/supabaseAuthUtils.ts) for reference # Supabase Integration Introduction > Learn how to integrate Supabase Authentication with the Capacitor Social Login plugin for a complete authentication solution. ## Overview [Section titled “Overview”](#overview) This tutorial will guide you through setting up Supabase Authentication with the Capacitor Social Login plugin. This integration allows you to use native social login providers (Google, Apple, Facebook, Twitter) on mobile platforms while leveraging Supabase Auth for backend authentication and PostgreSQL for data storage. ## What You’ll Learn [Section titled “What You’ll Learn”](#what-youll-learn) * How to configure Supabase Authentication * How to integrate Capacitor Social Login plugin with Supabase Auth * Platform-specific setup for Android, iOS, and Web * How to handle nonces securely for Supabase ## What You’ll Need [Section titled “What You’ll Need”](#what-youll-need) Before you begin, make sure you have: 1. **A Supabase Project** * Create a project at [Supabase Dashboard](https://app.supabase.com/) * Enable Google OAuth provider * Get your Supabase project URL and anon key 2. **Supabase JS SDK** * Install Supabase in your project: ```bash npm install @supabase/supabase-js ``` 3. **A Capacitor Project** * An existing Capacitor application * Capacitor Social Login plugin installed: ```bash npm install @capgo/capacitor-social-login npx cap sync ``` 4. **Platform-Specific Google Setup** * Complete the Google Sign-In setup for your target platforms: * [Google Login Android Setup](/docs/plugins/social-login/google/android/) * [Google Login iOS Setup](/docs/plugins/social-login/google/ios/) * [Google Login Web Setup](/docs/plugins/social-login/google/web/) ## Example Application [Section titled “Example Application”](#example-application) A complete working example is available in the repository: **Code Repository**: [You can find the code repository here](https://github.com/Cap-go/capacitor-social-login/tree/main/example-app) The example app demonstrates: * Email/password authentication with Supabase * Google Sign-In integration (Android, iOS, and Web) * A simple key-value store using Supabase PostgreSQL tables * User-specific data storage with Row Level Security (RLS) ## Key Implementation Details [Section titled “Key Implementation Details”](#key-implementation-details) ### Nonce Handling [Section titled “Nonce Handling”](#nonce-handling) Supabase requires special nonce handling for security. The implementation follows the [React Native Google Sign In documentation](https://react-native-google-signin.github.io/docs/security#usage-with-supabase): * Generate a `rawNonce` (URL-safe random string) * Hash it with SHA-256 to get `nonceDigest` * Pass `nonceDigest` to Google Sign-In * Pass `rawNonce` to Supabase (Supabase hashes it internally for comparison) ### JWT Validation [Section titled “JWT Validation”](#jwt-validation) The example implementation includes JWT validation to ensure: * The token audience matches your configured Google Client IDs * The nonce matches the expected digest * Automatic retry on validation failure (especially important for iOS) ### Platform-Specific Considerations [Section titled “Platform-Specific Considerations”](#platform-specific-considerations) * **iOS**: Token caching can cause nonce issues - the implementation handles this automatically * **Web**: Must call `isLoggedIn()` on mount to handle OAuth redirects * **Android**: Standard implementation with SHA-1 fingerprint configuration ## Next Steps [Section titled “Next Steps”](#next-steps) Continue with the setup guides: * [Supabase Google Login - General Setup](../google/general/) - Overview and prerequisites * [Android Setup](../google/android/) - Android-specific configuration * [iOS Setup](../google/ios/) - iOS-specific configuration * [Web Setup](../google/web/) - Web-specific configuration ### Apple Sign-In [Section titled “Apple Sign-In”](#apple-sign-in) * [Supabase Apple Login - General Setup](/docs/plugins/social-login/supabase/apple/general/) - Overview and prerequisites * [iOS Setup](/docs/plugins/social-login/supabase/apple/ios/) - iOS-specific configuration * [Android Setup](/docs/plugins/social-login/supabase/apple/android/) - Android-specific configuration # @capgo/capacitor-speech-recognition > Capacitor plugin for comprehensive on-device speech recognition with live partial results. ## Overview [Section titled “Overview”](#overview) Capacitor plugin for comprehensive on-device speech recognition with live partial results. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `available` - Checks whether the native speech recognition service is usable on the current device. * `isOnDeviceRecognitionAvailable` - Checks whether the platform’s newer on-device recognition path is available for the selected locale. * `start` - Begins capturing audio and transcribing speech. * `stop` - Stops listening and tears down native resources. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | -------------------------------- | ---------------------------------------------------------------------------------------------------- | | `available` | Checks whether the native speech recognition service is usable on the current device. | | `isOnDeviceRecognitionAvailable` | Checks whether the platform’s newer on-device recognition path is available for the selected locale. | | `start` | Begins capturing audio and transcribing speech. | | `stop` | Stops listening and tears down native resources. | | `forceStop` | Force stops the current session. | | `getLastPartialResult` | Gets the last cached partial transcription result. | | `setPTTState` | Updates the current push-to-talk button state. | | `getSupportedLanguages` | Gets the locales supported by the underlying recognizer. | | `isListening` | Returns whether the plugin is actively listening for speech. | | `checkPermissions` | Gets the current permission state. | | `requestPermissions` | Requests the microphone + speech recognition permissions. | | `getPluginVersion` | Returns the native plugin version bundled with this package. | | `addListener` | Listen for segmented session completion events (Android only). | | `addListener` | Listen for segmented recognition results (Android only). | | `addListener` | Listen for partial transcription updates emitted while `partialResults` is enabled. | | `addListener` | Listen for changes to the native listening state. | | `addListener` | Listen for recognition errors. | | `addListener` | Listen for the recognizer becoming ready for another session. | | `removeAllListeners` | Removes every registered listener. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-speech-recognition](https://github.com/Cap-go/capacitor-speech-recognition/). # Getting Started > Install @capgo/capacitor-speech-recognition and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-speech-recognition bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { SpeechRecognition } from '@capgo/capacitor-speech-recognition'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `available` [Section titled “available”](#available) Checks whether the native speech recognition service is usable on the current device. ```typescript import { SpeechRecognition } from '@capgo/capacitor-speech-recognition'; await SpeechRecognition.available(); ``` ### `isOnDeviceRecognitionAvailable` [Section titled “isOnDeviceRecognitionAvailable”](#isondevicerecognitionavailable) Checks whether the platform’s newer on-device recognition path is available for the selected locale. This is the capability check you should use before enabling `useOnDeviceRecognition`. A `true` result means the current device, OS version, and locale can use the newer on-device path for that platform. Returns `false` when the device only supports the legacy recognizer path. Platform SDK docs: iOS: [Speech](https://developer.apple.com/documentation/speech) Android: [SpeechRecognizer](https://developer.android.com/reference/android/speech/SpeechRecognizer) ```typescript import { SpeechRecognition } from '@capgo/capacitor-speech-recognition'; await SpeechRecognition.isOnDeviceRecognitionAvailable(); ``` ### `start` [Section titled “start”](#start) Begins capturing audio and transcribing speech. When `partialResults` is `true`, the returned promise resolves immediately and updates are streamed through the `partialResults` listener until the session ends. The default path keeps the legacy recognizer behavior for backward compatibility. Pass `useOnDeviceRecognition: true` only after checking . ```typescript import { SpeechRecognition } from '@capgo/capacitor-speech-recognition'; await SpeechRecognition.start(); ``` ### `stop` [Section titled “stop”](#stop) Stops listening and tears down native resources. ```typescript import { SpeechRecognition } from '@capgo/capacitor-speech-recognition'; await SpeechRecognition.stop(); ``` ### `forceStop` [Section titled “forceStop”](#forcestop) Force stops the current session. On Android, this first tries a normal stop and then falls back to destroy/recreate after `timeout`. On iOS, the current session is stopped immediately. If a partial transcript is cached, it is emitted through the `partialResults` listener with `forced: true`. ```typescript import { SpeechRecognition } from '@capgo/capacitor-speech-recognition'; await SpeechRecognition.forceStop(); ``` ### `getLastPartialResult` [Section titled “getLastPartialResult”](#getlastpartialresult) Gets the last cached partial transcription result. ```typescript import { SpeechRecognition } from '@capgo/capacitor-speech-recognition'; await SpeechRecognition.getLastPartialResult(); ``` ### `setPTTState` [Section titled “setPTTState”](#setpttstate) Updates the current push-to-talk button state. Use this together with `continuousPTT` or with a custom hold-to-talk flow. ```typescript import { SpeechRecognition } from '@capgo/capacitor-speech-recognition'; await SpeechRecognition.setPTTState({} as PTTStateOptions); ``` ### `getSupportedLanguages` [Section titled “getSupportedLanguages”](#getsupportedlanguages) Gets the locales supported by the underlying recognizer. Android 13+ devices no longer expose this list; in that case `languages` is empty. ```typescript import { SpeechRecognition } from '@capgo/capacitor-speech-recognition'; await SpeechRecognition.getSupportedLanguages(); ``` ### `isListening` [Section titled “isListening”](#islistening) Returns whether the plugin is actively listening for speech. ```typescript import { SpeechRecognition } from '@capgo/capacitor-speech-recognition'; await SpeechRecognition.isListening(); ``` ### `checkPermissions` [Section titled “checkPermissions”](#checkpermissions) Gets the current permission state. ```typescript import { SpeechRecognition } from '@capgo/capacitor-speech-recognition'; await SpeechRecognition.checkPermissions(); ``` ### `requestPermissions` [Section titled “requestPermissions”](#requestpermissions) Requests the microphone + speech recognition permissions. ```typescript import { SpeechRecognition } from '@capgo/capacitor-speech-recognition'; await SpeechRecognition.requestPermissions(); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `SpeechRecognitionAvailability` [Section titled “SpeechRecognitionAvailability”](#speechrecognitionavailability) ```typescript export interface SpeechRecognitionAvailability { available: boolean; } ``` ### `SpeechRecognitionStartOptions` [Section titled “SpeechRecognitionStartOptions”](#speechrecognitionstartoptions) Configure how the recognizer behaves when calling . ```typescript export interface SpeechRecognitionStartOptions { /** * Locale identifier such as `en-US`. When omitted the device language is used. */ language?: string; /** * Maximum number of final matches returned by native APIs. Defaults to `5`. */ maxResults?: number; /** * Prompt message shown inside the Android system dialog (ignored on iOS). */ prompt?: string; /** * When `true`, Android shows the OS speech dialog instead of running inline recognition. * Defaults to `false`. */ popup?: boolean; /** * Emits partial transcription updates through the `partialResults` listener while audio is captured. */ partialResults?: boolean; /** * Enables native punctuation handling where supported (iOS 16+). */ addPunctuation?: boolean; /** * Opt in to the platform's newer on-device recognition path when available. * * On iOS 26+, this uses Apple's `SpeechAnalyzer` / `SpeechTranscriber` pipeline. * On recent Android versions, this uses the on-device `SpeechRecognizer` path. * * It is intentionally opt-in so existing apps keep the legacy flow unless they choose * to roll out the new behavior. * * Use {@link SpeechRecognitionPlugin.isOnDeviceRecognitionAvailable} before enabling it in production. * * Platform SDK docs: * iOS: [Speech](https://developer.apple.com/documentation/speech), * [SpeechAnalyzer](https://developer.apple.com/documentation/speech/speechanalyzer), * [SpeechTranscriber](https://developer.apple.com/documentation/speech/speechtranscriber) * Android: [SpeechRecognizer](https://developer.android.com/reference/android/speech/SpeechRecognizer) * * Defaults to `false`. */ useOnDeviceRecognition?: boolean; /** * Allow a number of milliseconds of silence before splitting the recognition session into segments. * Required to be greater than zero and currently supported on Android only. */ allowForSilence?: number; /** * EXPERIMENTAL: Keep a PTT session alive across silence by restarting recognition while the button stays held. * * This restart behavior is implemented for Android inline recognition and iOS native recognition. */ continuousPTT?: boolean; } ``` ### `SpeechRecognitionMatches` [Section titled “SpeechRecognitionMatches”](#speechrecognitionmatches) ```typescript export interface SpeechRecognitionMatches { matches?: string[]; } ``` ### `ForceStopOptions` [Section titled “ForceStopOptions”](#forcestopoptions) Options for . ```typescript export interface ForceStopOptions { /** * Android only: timeout in milliseconds before forcing stop via destroy/recreate. * * On iOS, the current session is stopped immediately and this value is ignored. * * Defaults to `1500`. */ timeout?: number; } ``` ### `LastPartialResult` [Section titled “LastPartialResult”](#lastpartialresult) Result from . ```typescript export interface LastPartialResult { /** * Whether a partial result is currently cached. */ available: boolean; /** * The most recent transcript text known to the native recognizer. */ text: string; /** * All current match alternatives when available. */ matches?: string[]; } ``` ### `PTTStateOptions` [Section titled “PTTStateOptions”](#pttstateoptions) Options for . ```typescript export interface PTTStateOptions { /** * Whether the PTT button is currently held. */ held: boolean; } ``` ### `SpeechRecognitionLanguages` [Section titled “SpeechRecognitionLanguages”](#speechrecognitionlanguages) ```typescript export interface SpeechRecognitionLanguages { languages: string[]; } ``` ### `SpeechRecognitionListening` [Section titled “SpeechRecognitionListening”](#speechrecognitionlistening) ```typescript export interface SpeechRecognitionListening { listening: boolean; } ``` ### `SpeechRecognitionPermissionStatus` [Section titled “SpeechRecognitionPermissionStatus”](#speechrecognitionpermissionstatus) Permission map returned by `checkPermissions` and `requestPermissions`. ```typescript export interface SpeechRecognitionPermissionStatus { speechRecognition: PermissionState; } ``` ### `SpeechRecognitionSegmentResultEvent` [Section titled “SpeechRecognitionSegmentResultEvent”](#speechrecognitionsegmentresultevent) Raised whenever a segmented result is produced (Android only). ```typescript export interface SpeechRecognitionSegmentResultEvent { matches: string[]; } ``` ### `SpeechRecognitionPartialResultEvent` [Section titled “SpeechRecognitionPartialResultEvent”](#speechrecognitionpartialresultevent) Raised whenever a partial transcription is produced. ```typescript export interface SpeechRecognitionPartialResultEvent { /** * Current recognition matches when the native recognizer reports them. * * This can be omitted for forced or accumulated-only payloads. */ matches?: string[]; /** * Accumulated transcription from earlier continuous PTT cycles. */ accumulated?: string; /** * Final accumulated text including the current result. */ accumulatedText?: string; /** * `true` when the plugin is restarting recognition inside a continuous PTT session. */ isRestarting?: boolean; /** * `true` when the payload was emitted by `forceStop()`. */ forced?: boolean; } ``` ### `SpeechRecognitionListeningEvent` [Section titled “SpeechRecognitionListeningEvent”](#speechrecognitionlisteningevent) Raised when the listening state changes. ```typescript export interface SpeechRecognitionListeningEvent { /** * Finite state of the recognition session. */ state?: ListeningFiniteState; /** * Unique identifier for the current listening session. */ sessionId?: number; /** * Why this state transition occurred. */ reason?: ListeningReason; /** * Error code when the transition is caused by an error. */ errorCode?: string; /** * Backward-compatible binary state used by earlier releases. */ status?: 'started' | 'stopped'; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-speech-synthesis > Speech Synthesis Plugin for synthesizing speech from text. ## Overview [Section titled “Overview”](#overview) Speech Synthesis Plugin for synthesizing speech from text. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `speak` - Speaks the given text with specified options. The utterance is added to the speech queue. * `synthesizeToFile` - Synthesizes speech to an audio file (Android/iOS only). Returns the file path where the audio was saved. * `cancel` - Cancels all queued utterances and stops current speech. * `pause` - Pauses speech immediately. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------------ | ----------------------------------------------------------------------------------------------------------------- | | `speak` | Speaks the given text with specified options. The utterance is added to the speech queue. | | `synthesizeToFile` | Synthesizes speech to an audio file (Android/iOS only). Returns the file path where the audio was saved. | | `cancel` | Cancels all queued utterances and stops current speech. | | `pause` | Pauses speech immediately. | | `resume` | Resumes paused speech. | | `isSpeaking` | Checks if speech synthesis is currently speaking. | | `isAvailable` | Checks if speech synthesis is available on the device. | | `getVoices` | Gets all available voices. | | `getLanguages` | Gets all available languages. | | `isLanguageAvailable` | Checks if a specific language is available. | | `isVoiceAvailable` | Checks if a specific voice is available. | | `initialize` | Initializes the speech synthesis engine (iOS optimization). This can reduce latency for the first speech request. | | `activateAudioSession` | Activates the audio session with a specific category (iOS only). | | `deactivateAudioSession` | Deactivates the audio session (iOS only). | | `getPluginVersion` | Gets the native plugin version. | | `addListener` | Listens for when an utterance starts speaking. | | `addListener` | Listens for when an utterance finishes speaking. | | `addListener` | Listens for word boundaries during speech. | | `addListener` | Listens for synthesis errors. | | `removeAllListeners` | Removes all event listeners. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-speech-synthesis](https://github.com/Cap-go/capacitor-speech-synthesis/). # Getting Started > Install @capgo/capacitor-speech-synthesis and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-speech-synthesis bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { SpeechSynthesis } from '@capgo/capacitor-speech-synthesis'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `speak` [Section titled “speak”](#speak) Speaks the given text with specified options. The utterance is added to the speech queue. ```typescript import { SpeechSynthesis } from '@capgo/capacitor-speech-synthesis'; const result = await SpeechSynthesis.speak({ text: 'Hello, world!', language: 'en-US', rate: 1.0, pitch: 1.0, volume: 1.0, queueStrategy: 'Add' }); console.log('Utterance ID:', result.utteranceId); ``` ### `synthesizeToFile` [Section titled “synthesizeToFile”](#synthesizetofile) Synthesizes speech to an audio file (Android/iOS only). Returns the file path where the audio was saved. ```typescript import { SpeechSynthesis } from '@capgo/capacitor-speech-synthesis'; const result = await SpeechSynthesis.synthesizeToFile({ text: 'Hello, world!', language: 'en-US' }); console.log('Audio file saved at:', result.filePath); ``` ### `cancel` [Section titled “cancel”](#cancel) Cancels all queued utterances and stops current speech. ```typescript import { SpeechSynthesis } from '@capgo/capacitor-speech-synthesis'; await SpeechSynthesis.cancel(); ``` ### `pause` [Section titled “pause”](#pause) Pauses speech immediately. ```typescript import { SpeechSynthesis } from '@capgo/capacitor-speech-synthesis'; await SpeechSynthesis.pause(); ``` ### `resume` [Section titled “resume”](#resume) Resumes paused speech. ```typescript import { SpeechSynthesis } from '@capgo/capacitor-speech-synthesis'; await SpeechSynthesis.resume(); ``` ### `isSpeaking` [Section titled “isSpeaking”](#isspeaking) Checks if speech synthesis is currently speaking. ```typescript import { SpeechSynthesis } from '@capgo/capacitor-speech-synthesis'; const { isSpeaking } = await SpeechSynthesis.isSpeaking(); console.log('Is speaking:', isSpeaking); ``` ### `isAvailable` [Section titled “isAvailable”](#isavailable) Checks if speech synthesis is available on the device. ```typescript import { SpeechSynthesis } from '@capgo/capacitor-speech-synthesis'; const { isAvailable } = await SpeechSynthesis.isAvailable(); if (isAvailable) { console.log('Speech synthesis is available'); } ``` ### `getVoices` [Section titled “getVoices”](#getvoices) Gets all available voices. ```typescript import { SpeechSynthesis } from '@capgo/capacitor-speech-synthesis'; const { voices } = await SpeechSynthesis.getVoices(); voices.forEach(voice => { console.log(`${voice.name} (${voice.language})`); }); ``` ### `getLanguages` [Section titled “getLanguages”](#getlanguages) Gets all available languages. ```typescript import { SpeechSynthesis } from '@capgo/capacitor-speech-synthesis'; const { languages } = await SpeechSynthesis.getLanguages(); console.log('Available languages:', languages); ``` ### `isLanguageAvailable` [Section titled “isLanguageAvailable”](#islanguageavailable) Checks if a specific language is available. ```typescript import { SpeechSynthesis } from '@capgo/capacitor-speech-synthesis'; const { isAvailable } = await SpeechSynthesis.isLanguageAvailable({ language: 'es-ES' }); console.log('Spanish available:', isAvailable); ``` ### `isVoiceAvailable` [Section titled “isVoiceAvailable”](#isvoiceavailable) Checks if a specific voice is available. ```typescript import { SpeechSynthesis } from '@capgo/capacitor-speech-synthesis'; const { isAvailable } = await SpeechSynthesis.isVoiceAvailable({ voiceId: 'com.apple.ttsbundle.Samantha-compact' }); console.log('Voice available:', isAvailable); ``` ### `initialize` [Section titled “initialize”](#initialize) Initializes the speech synthesis engine (iOS optimization). This can reduce latency for the first speech request. ```typescript import { SpeechSynthesis } from '@capgo/capacitor-speech-synthesis'; await SpeechSynthesis.initialize(); ``` ### `activateAudioSession` [Section titled “activateAudioSession”](#activateaudiosession) Activates the audio session with a specific category (iOS only). ```typescript import { SpeechSynthesis } from '@capgo/capacitor-speech-synthesis'; await SpeechSynthesis.activateAudioSession({ category: 'Playback' }); ``` ### `deactivateAudioSession` [Section titled “deactivateAudioSession”](#deactivateaudiosession) Deactivates the audio session (iOS only). ```typescript import { SpeechSynthesis } from '@capgo/capacitor-speech-synthesis'; await SpeechSynthesis.deactivateAudioSession(); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `SpeakOptions` [Section titled “SpeakOptions”](#speakoptions) Options for speaking text. ```typescript export interface SpeakOptions { /** * The text to speak. * * @since 1.0.0 */ text: string; /** * The BCP-47 language tag (e.g., 'en-US', 'es-ES'). * * @since 1.0.0 */ language?: string; /** * The voice identifier to use. * * @since 1.0.0 */ voiceId?: string; /** * The pitch of the voice (0.5 to 2.0, default: 1.0). * * @since 1.0.0 */ pitch?: number; /** * The speaking rate (0.1 to 10.0, default: 1.0). * * @since 1.0.0 */ rate?: number; /** * The volume (0.0 to 1.0, default: 1.0). * * @since 1.0.0 */ volume?: number; /** * The queue strategy: 'Add' to append or 'Flush' to replace queue. * Default: 'Add' * * @since 1.0.0 */ queueStrategy?: 'Add' | 'Flush'; } ``` ### `SpeakResult` [Section titled “SpeakResult”](#speakresult) Result from speaking text. ```typescript export interface SpeakResult { /** * Unique identifier for this utterance. * * @since 1.0.0 */ utteranceId: string; } ``` ### `SynthesizeToFileResult` [Section titled “SynthesizeToFileResult”](#synthesizetofileresult) Result from synthesizing to file. ```typescript export interface SynthesizeToFileResult { /** * The file path where audio was saved. * * @since 1.0.0 */ filePath: string; /** * Unique identifier for this utterance. * * @since 1.0.0 */ utteranceId: string; } ``` ### `VoiceInfo` [Section titled “VoiceInfo”](#voiceinfo) Information about a voice. ```typescript export interface VoiceInfo { /** * Unique voice identifier. * * @since 1.0.0 */ id: string; /** * Display name of the voice. * * @since 1.0.0 */ name: string; /** * BCP-47 language code. * * @since 1.0.0 */ language: string; /** * Gender of the voice (iOS only). * * @since 1.0.0 */ gender?: 'male' | 'female' | 'neutral'; /** * Whether this voice requires a network connection. * * @since 1.0.0 */ isNetworkConnectionRequired?: boolean; /** * Whether this is the default voice (Web only). * * @since 1.0.0 */ default?: boolean; } ``` ### `IsLanguageAvailableOptions` [Section titled “IsLanguageAvailableOptions”](#islanguageavailableoptions) Options for checking language availability. ```typescript export interface IsLanguageAvailableOptions { /** * The BCP-47 language code to check. * * @since 1.0.0 */ language: string; } ``` ### `IsVoiceAvailableOptions` [Section titled “IsVoiceAvailableOptions”](#isvoiceavailableoptions) Options for checking voice availability. ```typescript export interface IsVoiceAvailableOptions { /** * The voice ID to check. * * @since 1.0.0 */ voiceId: string; } ``` ### `ActivateAudioSessionOptions` [Section titled “ActivateAudioSessionOptions”](#activateaudiosessionoptions) Options for activating the audio session (iOS only). ```typescript export interface ActivateAudioSessionOptions { /** * The audio session category. * - 'Ambient': Mixes with other audio * - 'Playback': Stops other audio * * @since 1.0.0 */ category: 'Ambient' | 'Playback'; } ``` ### `UtteranceEvent` [Section titled “UtteranceEvent”](#utteranceevent) Event emitted when utterance starts or ends. ```typescript export interface UtteranceEvent { /** * The utterance identifier. * * @since 1.0.0 */ utteranceId: string; } ``` ### `BoundaryEvent` [Section titled “BoundaryEvent”](#boundaryevent) Event emitted at word boundaries. ```typescript export interface BoundaryEvent { /** * The utterance identifier. * * @since 1.0.0 */ utteranceId: string; /** * The character index in the text. * * @since 1.0.0 */ charIndex: number; /** * The character length of the current word. * * @since 1.0.0 */ charLength?: number; } ``` ### `ErrorEvent` [Section titled “ErrorEvent”](#errorevent) Event emitted on synthesis error. ```typescript export interface ErrorEvent { /** * The utterance identifier. * * @since 1.0.0 */ utteranceId: string; /** * The error message. * * @since 1.0.0 */ error: string; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-ssl-pinning > Capacitor API for inspecting SSL pinning configuration. ## Overview [Section titled “Overview”](#overview) Capacitor API for inspecting SSL pinning configuration. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `getConfiguration` - Returns the active native configuration visible to the plugin. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------ | -------------------------------------------------------------- | | `getConfiguration` | Returns the active native configuration visible to the plugin. | | `getPluginVersion` | Returns the native implementation version marker. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-ssl-pinning](https://github.com/Cap-go/capacitor-ssl-pinning/). # Getting Started > Install @capgo/capacitor-ssl-pinning and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-ssl-pinning bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { SSLPinning } from '@capgo/capacitor-ssl-pinning'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `getConfiguration` [Section titled “getConfiguration”](#getconfiguration) Returns the active native configuration visible to the plugin. ```typescript import { SSLPinning } from '@capgo/capacitor-ssl-pinning'; await SSLPinning.getConfiguration(); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `SSLPinningConfigurationState` [Section titled “SSLPinningConfigurationState”](#sslpinningconfigurationstate) Static SSL pinning configuration currently visible to the plugin. ```typescript export interface SSLPinningConfigurationState { /** * Whether at least one certificate is configured for native pinning. */ configured: boolean; /** * Certificate paths from `capacitor.config.*` relative to the app root. */ certs: string[]; /** * Fully-qualified URLs that should bypass SSL pinning. */ excludedDomains: string[]; } ``` ### `PluginVersionResult` [Section titled “PluginVersionResult”](#pluginversionresult) Plugin version payload. ```typescript export interface PluginVersionResult { /** * Version identifier returned by the platform implementation. */ version: string; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-stream-call > Uses the https://getstream.io/ SDK to implement calling in Capacitor. ## Overview [Section titled “Overview”](#overview) Uses the <https://getstream.io/> SDK to implement calling in Capacitor. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `login` - Login to Stream Video service. * `logout` - Logout from Stream Video service. * `call` - Initiate a call to another user. * `endCall` - End the current call. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | | `login` | Login to Stream Video service. | | `logout` | Logout from Stream Video service. | | `call` | Initiate a call to another user. | | `endCall` | End the current call. | | `joinCall` | Join an existing call. | | `setMicrophoneEnabled` | Enable or disable microphone. | | `setCameraEnabled` | Enable or disable camera. | | `addListener` | Add listener for call events. | | `addListener` | Listen for lock-screen incoming call (Android only). Fired when the app is shown by full-screen intent before user interaction. | | `removeAllListeners` | Remove all event listeners. | | `enableBluetooth` | Enable bluetooth audio. | | `acceptCall` | Accept an incoming call. | | `rejectCall` | Reject an incoming call. | | `isCameraEnabled` | Check if camera is enabled. | | `getCallStatus` | Get the current call status. | | `getRingingCall` | Get the current ringing call. | | `toggleViews` | Cycle through the available video layouts. | | `setSpeaker` | Set speakerphone on. | | `switchCamera` | Switch camera. | | `getCallInfo` | Get detailed information about an active call including caller details. | | `setDynamicStreamVideoApikey` | Set a dynamic Stream Video API key that overrides the static one. | | `getDynamicStreamVideoApikey` | Get the currently set dynamic Stream Video API key. | | `getCurrentUser` | Get the current user’s information. | | `getPluginVersion` | Get the native Capacitor plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-streamcall](https://github.com/Cap-go/capacitor-streamcall/). # Getting Started > Install @capgo/capacitor-stream-call and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-stream-call bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { StreamCall } from '@capgo/capacitor-stream-call'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `login` [Section titled “login”](#login) Login to Stream Video service ```typescript import { StreamCall } from '@capgo/capacitor-stream-call'; await StreamCall.login({ token: 'your-token', userId: 'user-123', name: 'John Doe', apiKey: 'your-api-key' }); ``` ### `logout` [Section titled “logout”](#logout) Logout from Stream Video service ```typescript import { StreamCall } from '@capgo/capacitor-stream-call'; await StreamCall.logout(); ``` ### `call` [Section titled “call”](#call) Initiate a call to another user ```typescript import { StreamCall } from '@capgo/capacitor-stream-call'; await StreamCall.call({ userId: 'user-456', type: 'video', ring: true }); ``` ### `endCall` [Section titled “endCall”](#endcall) End the current call ```typescript import { StreamCall } from '@capgo/capacitor-stream-call'; await StreamCall.endCall(); ``` ### `joinCall` [Section titled “joinCall”](#joincall) Join an existing call ```typescript import { StreamCall } from '@capgo/capacitor-stream-call'; await StreamCall.joinCall({ callId: 'call001', callType: 'default' }); ``` ### `setMicrophoneEnabled` [Section titled “setMicrophoneEnabled”](#setmicrophoneenabled) Enable or disable microphone ```typescript import { StreamCall } from '@capgo/capacitor-stream-call'; await StreamCall.setMicrophoneEnabled({ enabled: false }); ``` ### `setCameraEnabled` [Section titled “setCameraEnabled”](#setcameraenabled) Enable or disable camera ```typescript import { StreamCall } from '@capgo/capacitor-stream-call'; await StreamCall.setCameraEnabled({ enabled: false }); ``` ### `enableBluetooth` [Section titled “enableBluetooth”](#enablebluetooth) Enable bluetooth audio ```typescript import { StreamCall } from '@capgo/capacitor-stream-call'; await StreamCall.enableBluetooth(); ``` ### `acceptCall` [Section titled “acceptCall”](#acceptcall) Accept an incoming call ```typescript import { StreamCall } from '@capgo/capacitor-stream-call'; await StreamCall.acceptCall(); ``` ### `rejectCall` [Section titled “rejectCall”](#rejectcall) Reject an incoming call ```typescript import { StreamCall } from '@capgo/capacitor-stream-call'; await StreamCall.rejectCall(); ``` ### `isCameraEnabled` [Section titled “isCameraEnabled”](#iscameraenabled) Check if camera is enabled ```typescript import { StreamCall } from '@capgo/capacitor-stream-call'; const isCameraEnabled = await StreamCall.isCameraEnabled(); console.log(isCameraEnabled); ``` ### `getCallStatus` [Section titled “getCallStatus”](#getcallstatus) Get the current call status ```typescript import { StreamCall } from '@capgo/capacitor-stream-call'; const callStatus = await StreamCall.getCallStatus(); console.log(callStatus); ``` ### `getRingingCall` [Section titled “getRingingCall”](#getringingcall) Get the current ringing call ```typescript import { StreamCall } from '@capgo/capacitor-stream-call'; const ringingCall = await StreamCall.getRingingCall(); console.log(ringingCall); ``` ### `toggleViews` [Section titled “toggleViews”](#toggleviews) Cycle through the available video layouts ```typescript import { StreamCall } from '@capgo/capacitor-stream-call'; const { newLayout } = await StreamCall.toggleViews(); console.log(`Layout switched to ${newLayout}`); ``` ### `setSpeaker` [Section titled “setSpeaker”](#setspeaker) Set speakerphone on ```typescript import { StreamCall } from '@capgo/capacitor-stream-call'; await StreamCall.setSpeaker({ name: 'speaker' }); ``` ### `switchCamera` [Section titled “switchCamera”](#switchcamera) Switch camera ```typescript import { StreamCall } from '@capgo/capacitor-stream-call'; await StreamCall.switchCamera({ camera: 'back' }); ``` ### `getCallInfo` [Section titled “getCallInfo”](#getcallinfo) Get detailed information about an active call including caller details ```typescript import { StreamCall } from '@capgo/capacitor-stream-call'; await StreamCall.getCallInfo({} as { callId: string }); ``` ### `setDynamicStreamVideoApikey` [Section titled “setDynamicStreamVideoApikey”](#setdynamicstreamvideoapikey) Set a dynamic Stream Video API key that overrides the static one ```typescript import { StreamCall } from '@capgo/capacitor-stream-call'; await StreamCall.setDynamicStreamVideoApikey({ apiKey: 'new-api-key' }); ``` ### `getDynamicStreamVideoApikey` [Section titled “getDynamicStreamVideoApikey”](#getdynamicstreamvideoapikey) Get the currently set dynamic Stream Video API key ```typescript import { StreamCall } from '@capgo/capacitor-stream-call'; const result = await StreamCall.getDynamicStreamVideoApikey(); if (result.hasDynamicKey) { console.log('Dynamic API key:', result.apiKey); } else { console.log('Using static API key from resources'); } ``` ### `getCurrentUser` [Section titled “getCurrentUser”](#getcurrentuser) Get the current user’s information ```typescript import { StreamCall } from '@capgo/capacitor-stream-call'; const currentUser = await StreamCall.getCurrentUser(); console.log(currentUser); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `LoginOptions` [Section titled “LoginOptions”](#loginoptions) ```typescript export interface LoginOptions { /** Stream Video API token */ token: string; /** User ID for the current user */ userId: string; /** Display name for the current user */ name: string; /** Optional avatar URL for the current user */ imageURL?: string; /** Stream Video API key */ apiKey: string; /** ID of the HTML element where the video will be rendered */ magicDivId?: string; pushNotificationsConfig?: PushNotificationsConfig; } ``` ### `SuccessResponse` [Section titled “SuccessResponse”](#successresponse) ```typescript export interface SuccessResponse { /** Whether the operation was successful */ success: boolean; callId?: string; } ``` ### `CallOptions` [Section titled “CallOptions”](#calloptions) ```typescript export interface CallOptions { /** User ID of the person to call */ userIds: string[]; /** Type of call, defaults to 'default' */ type?: CallType; /** Whether to ring the other user, defaults to true */ ring?: boolean; /** Team name to call */ team?: string; /** Whether to start the call with video enabled, defaults to false */ video?: boolean; /** Custom data to be passed to the call */ custom?: Record< string, | string | boolean | number | null | Record<string, string | boolean | number | null> | string[] | boolean[] | number[] >; } ``` ### `CallEvent` [Section titled “CallEvent”](#callevent) ```typescript export interface CallEvent { /** ID of the call */ callId: string; /** Current state of the call */ state: CallState; /** User ID of the participant in the call who triggered the event */ userId?: string; /** Reason for the call state change, if applicable */ reason?: string; /** Information about the caller (for incoming calls) */ caller?: CallMember; /** List of call members */ members?: CallMember[]; custom?: Record< string, | string | boolean | number | null | Record<string, string | boolean | number | null> | string[] | boolean[] | number[] >; count?: number; } ``` ### `IncomingCallPayload` [Section titled “IncomingCallPayload”](#incomingcallpayload) ```typescript export interface IncomingCallPayload { /** Full call CID (e.g. default:123) */ cid: string; /** Event type (currently always "incoming") */ type: 'incoming'; /** Information about the caller */ caller?: CallMember; /** Custom data to be passed to the call */ custom?: Record< string, | string | boolean | number | null | Record<string, string | boolean | number | null> | string[] | boolean[] | number[] >; /** * Get the native Capacitor plugin version * * @returns {Promise<{ id: string }>} an Promise with version for this device * @throws An error if the something went wrong */ getPluginVersion(): Promise<{ version: string }>; } ``` ### `CameraEnabledResponse` [Section titled “CameraEnabledResponse”](#cameraenabledresponse) ```typescript export interface CameraEnabledResponse { enabled: boolean; } ``` ### `StreamCallLayout` [Section titled “StreamCallLayout”](#streamcalllayout) ```typescript export type StreamCallLayout = 'grid' | 'spotlight' | 'dynamic' | 'fullScreen' | 'fullscreen'; ``` ### `DynamicApiKeyResponse` [Section titled “DynamicApiKeyResponse”](#dynamicapikeyresponse) ```typescript export interface DynamicApiKeyResponse { /** The dynamic API key if set, null if not */ apiKey: string | null; /** Whether a dynamic key is currently set */ hasDynamicKey: boolean; } ``` ### `CurrentUserResponse` [Section titled “CurrentUserResponse”](#currentuserresponse) ```typescript export interface CurrentUserResponse { /** User ID of the current user */ userId: string; /** Display name of the current user */ name: string; /** Avatar URL of the current user */ imageURL?: string; /** Whether the user is currently logged in */ isLoggedIn: boolean; } ``` ### `PushNotificationsConfig` [Section titled “PushNotificationsConfig”](#pushnotificationsconfig) ```typescript export interface PushNotificationsConfig { pushProviderName: string; voipProviderName: string; } ``` ### `CallType` [Section titled “CallType”](#calltype) ```typescript export type CallType = 'default' | 'audio' | 'audio_room' | 'livestream' | 'development'; ``` ### `CallState` [Section titled “CallState”](#callstate) ```typescript export type CallState = // User-facing states | 'idle' | 'ringing' | 'joining' | 'reconnecting' | 'joined' | 'leaving' | 'left' // Event-specific states | 'created' | 'session_started' | 'rejected' | 'participant_counts' | 'missed' | 'accepted' | 'ended' | 'camera_enabled' | 'camera_disabled' | 'speaker_enabled' | 'speaker_disabled' | 'microphone_enabled' | 'microphone_disabled' | 'outgoing_call_ended' | 'unknown'; ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-textinteraction > Toggle text interaction in Capacitor based iOS apps. ## Overview [Section titled “Overview”](#overview) Toggle text interaction in Capacitor based iOS apps. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `toggle` - Toggle text interaction (selection) on the Capacitor WebView. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------ | ------------------------------------------------------------- | | `toggle` | Toggle text interaction (selection) on the Capacitor WebView. | | `getPluginVersion` | Get the native Capacitor plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-textinteraction](https://github.com/Cap-go/capacitor-textinteraction/). # Getting Started > Install @capgo/capacitor-textinteraction and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-textinteraction bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { TextInteraction } from '@capgo/capacitor-textinteraction'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `toggle` [Section titled “toggle”](#toggle) Toggle text interaction (selection) on the Capacitor WebView. ⚠️ Disabling text interaction prevents all text input controls from working while disabled. Use it sparingly and re-enable when text entry is required. iOS only. ```typescript import { TextInteraction } from '@capgo/capacitor-textinteraction'; await TextInteraction.toggle({} as TextInteractionOptions); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `TextInteractionOptions` [Section titled “TextInteractionOptions”](#textinteractionoptions) ```typescript export interface TextInteractionOptions { /** * Whether text interaction should be enabled or disabled. Disabling hides the * magnifier lens reintroduced with iOS 15. */ enabled: boolean; } ``` ### `TextInteractionResult` [Section titled “TextInteractionResult”](#textinteractionresult) ```typescript export interface TextInteractionResult { /** * `true` when the platform supports toggling text interaction (iOS >= 14.5), otherwise `false`. */ success: boolean; /** * Get the native Capacitor plugin version * * @returns {Promise<{ id: string }>} an Promise with version for this device * @throws An error if the something went wrong */ getPluginVersion(): Promise<{ version: string }>; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-twilio-video > Capacitor API for joining Twilio Video rooms with a native in-app call surface. ## Overview [Section titled “Overview”](#overview) Capacitor API for joining Twilio Video rooms with a native in-app call surface. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `login` - Store and validate a Twilio Video access token minted by your backend. * `logout` - Clear the cached access token and leave the active room. * `isLoggedIn` - Check whether a valid Twilio token is currently cached on the device. * `joinRoom` - Join a Twilio room and present the plugin’s native in-app call overlay. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ----------------------------- | ----------------------------------------------------------------------- | | `login` | Store and validate a Twilio Video access token minted by your backend. | | `logout` | Clear the cached access token and leave the active room. | | `isLoggedIn` | Check whether a valid Twilio token is currently cached on the device. | | `joinRoom` | Join a Twilio room and present the plugin’s native in-app call overlay. | | `leaveRoom` | Leave the current room if connected. | | `setMicrophoneEnabled` | Enable/disable local microphone publishing. | | `setCameraEnabled` | Enable/disable local camera publishing. | | `getCallStatus` | Return the current room name, media state, and participant count. | | `checkMicrophonePermission` | Check microphone permission state. | | `requestMicrophonePermission` | Request microphone permission. | | `checkCameraPermission` | Check camera permission state. | | `requestCameraPermission` | Request camera permission. | | `addListener` | Listen for room connected events. | | `addListener` | Listen for room disconnected events. | | `addListener` | Listen for participant connected events. | | `addListener` | Listen for participant disconnected events. | | `addListener` | Listen for reconnection start events. | | `addListener` | Listen for reconnection success events. | | `removeAllListeners` | Remove every listener registered through this plugin instance. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-twilio-video](https://github.com/Cap-go/capacitor-twilio-video/). # Getting Started > Install @capgo/capacitor-twilio-video and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-twilio-video bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { CapacitorTwilioVideo } from '@capgo/capacitor-twilio-video'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `login` [Section titled “login”](#login) Store and validate a Twilio Video access token minted by your backend. ```typescript import { CapacitorTwilioVideo } from '@capgo/capacitor-twilio-video'; await CapacitorTwilioVideo.login({} as { accessToken: string }); ``` ### `logout` [Section titled “logout”](#logout) Clear the cached access token and leave the active room. ```typescript import { CapacitorTwilioVideo } from '@capgo/capacitor-twilio-video'; await CapacitorTwilioVideo.logout(); ``` ### `isLoggedIn` [Section titled “isLoggedIn”](#isloggedin) Check whether a valid Twilio token is currently cached on the device. ```typescript import { CapacitorTwilioVideo } from '@capgo/capacitor-twilio-video'; await CapacitorTwilioVideo.isLoggedIn(); ``` ### `joinRoom` [Section titled “joinRoom”](#joinroom) Join a Twilio room and present the plugin’s native in-app call overlay. ```typescript import { CapacitorTwilioVideo } from '@capgo/capacitor-twilio-video'; await CapacitorTwilioVideo.joinRoom({} as { roomName: string; enableAudio?: boolean; enableVideo?: boolean }); ``` ### `leaveRoom` [Section titled “leaveRoom”](#leaveroom) Leave the current room if connected. ```typescript import { CapacitorTwilioVideo } from '@capgo/capacitor-twilio-video'; await CapacitorTwilioVideo.leaveRoom(); ``` ### `setMicrophoneEnabled` [Section titled “setMicrophoneEnabled”](#setmicrophoneenabled) Enable/disable local microphone publishing. ```typescript import { CapacitorTwilioVideo } from '@capgo/capacitor-twilio-video'; await CapacitorTwilioVideo.setMicrophoneEnabled({} as { enabled: boolean }); ``` ### `setCameraEnabled` [Section titled “setCameraEnabled”](#setcameraenabled) Enable/disable local camera publishing. ```typescript import { CapacitorTwilioVideo } from '@capgo/capacitor-twilio-video'; await CapacitorTwilioVideo.setCameraEnabled({} as { enabled: boolean }); ``` ### `getCallStatus` [Section titled “getCallStatus”](#getcallstatus) Return the current room name, media state, and participant count. ```typescript import { CapacitorTwilioVideo } from '@capgo/capacitor-twilio-video'; await CapacitorTwilioVideo.getCallStatus(); ``` ### `checkMicrophonePermission` [Section titled “checkMicrophonePermission”](#checkmicrophonepermission) Check microphone permission state. ```typescript import { CapacitorTwilioVideo } from '@capgo/capacitor-twilio-video'; await CapacitorTwilioVideo.checkMicrophonePermission(); ``` ### `requestMicrophonePermission` [Section titled “requestMicrophonePermission”](#requestmicrophonepermission) Request microphone permission. ```typescript import { CapacitorTwilioVideo } from '@capgo/capacitor-twilio-video'; await CapacitorTwilioVideo.requestMicrophonePermission(); ``` ### `checkCameraPermission` [Section titled “checkCameraPermission”](#checkcamerapermission) Check camera permission state. ```typescript import { CapacitorTwilioVideo } from '@capgo/capacitor-twilio-video'; await CapacitorTwilioVideo.checkCameraPermission(); ``` ### `requestCameraPermission` [Section titled “requestCameraPermission”](#requestcamerapermission) Request camera permission. ```typescript import { CapacitorTwilioVideo } from '@capgo/capacitor-twilio-video'; await CapacitorTwilioVideo.requestCameraPermission(); ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-twilio-voice > Integrates the Twilio Voice SDK into Capacitor. ## Overview [Section titled “Overview”](#overview) Integrates the Twilio Voice SDK into Capacitor. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `login` - Authenticate the user with Twilio Voice using an access token. * `logout` - Log out the current user and unregister from Twilio Voice. * `isLoggedIn` - Check if the user is currently logged in and has a valid access token. * `makeCall` - Initiate an outgoing call to a phone number or client. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ----------------------------- | ---------------------------------------------------------------------- | | `login` | Authenticate the user with Twilio Voice using an access token. | | `logout` | Log out the current user and unregister from Twilio Voice. | | `isLoggedIn` | Check if the user is currently logged in and has a valid access token. | | `makeCall` | Initiate an outgoing call to a phone number or client. | | `acceptCall` | Accept an incoming call. | | `rejectCall` | Reject an incoming call. | | `endCall` | End an active call. | | `muteCall` | Mute or unmute the microphone during an active call. | | `setSpeaker` | Enable or disable speakerphone mode. | | `getCallStatus` | Get the current status of the active call. | | `checkMicrophonePermission` | Check if microphone permission has been granted. | | `requestMicrophonePermission` | Request microphone permission from the user. | | `addListener` | Listen for incoming call invitations. | | `addListener` | Listen for call connected events. | | `addListener` | Listen for call invite cancellation events. | | `addListener` | Listen for outgoing call initiation events. | | `addListener` | Listen for outgoing call failure events. | | `addListener` | Listen for call disconnection events. | | `addListener` | Listen for call ringing events. | | `addListener` | Listen for call reconnecting events. | | `addListener` | Listen for call reconnected events. | | `addListener` | Listen for call quality warning events. | | `addListener` | Listen for successful registration events. | | `addListener` | Listen for registration failure events. | | `removeAllListeners` | Remove all registered event listeners. | | `getPluginVersion` | Get the native Capacitor plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-twilio-voice](https://github.com/Cap-go/capacitor-twilio-voice/). # Getting Started > Install @capgo/capacitor-twilio-voice and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-twilio-voice bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { CapacitorTwilioVoice } from '@capgo/capacitor-twilio-voice'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `login` [Section titled “login”](#login) Authenticate the user with Twilio Voice using an access token. The access token should be generated on your backend server using your Twilio credentials. This token is required to make and receive calls through Twilio Voice. ```typescript import { CapacitorTwilioVoice } from '@capgo/capacitor-twilio-voice'; const result = await CapacitorTwilioVoice.login({ accessToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...' }); console.log('Login successful:', result.success); ``` ### `logout` [Section titled “logout”](#logout) Log out the current user and unregister from Twilio Voice. This will disconnect any active calls and stop the device from receiving new incoming call notifications. ```typescript import { CapacitorTwilioVoice } from '@capgo/capacitor-twilio-voice'; const result = await CapacitorTwilioVoice.logout(); console.log('Logout successful:', result.success); ``` ### `isLoggedIn` [Section titled “isLoggedIn”](#isloggedin) Check if the user is currently logged in and has a valid access token. ```typescript import { CapacitorTwilioVoice } from '@capgo/capacitor-twilio-voice'; const status = await CapacitorTwilioVoice.isLoggedIn(); if (status.isLoggedIn && status.hasValidToken) { console.log('User identity:', status.identity); } else { // Re-authenticate the user } ``` ### `makeCall` [Section titled “makeCall”](#makecall) Initiate an outgoing call to a phone number or client. The user must be logged in before making a call. The call will be routed through your Twilio backend configuration. ```typescript import { CapacitorTwilioVoice } from '@capgo/capacitor-twilio-voice'; // Call a phone number const result = await CapacitorTwilioVoice.makeCall({ to: '+1234567890' }); console.log('Call SID:', result.callSid); // Call another Twilio client with a readable name for CallKit Recents await CapacitorTwilioVoice.makeCall({ to: 'client:alice', displayName: 'Alice Smith' }); // Call a PSTN number using a specific caller ID await CapacitorTwilioVoice.makeCall({ to: '+1234567890', callerId: '+10987654321' }); ``` ### `acceptCall` [Section titled “acceptCall”](#acceptcall) Accept an incoming call. This should be called in response to a ‘callInviteReceived’ event. ```typescript import { CapacitorTwilioVoice } from '@capgo/capacitor-twilio-voice'; CapacitorTwilioVoice.addListener('callInviteReceived', async (data) => { console.log('Incoming call from:', data.from); const result = await CapacitorTwilioVoice.acceptCall({ callSid: data.callSid }); console.log('Call accepted:', result.success); }); ``` ### `rejectCall` [Section titled “rejectCall”](#rejectcall) Reject an incoming call. This should be called in response to a ‘callInviteReceived’ event. The caller will hear a busy signal or be directed to voicemail. ```typescript import { CapacitorTwilioVoice } from '@capgo/capacitor-twilio-voice'; CapacitorTwilioVoice.addListener('callInviteReceived', async (data) => { if (shouldRejectCall(data.from)) { await CapacitorTwilioVoice.rejectCall({ callSid: data.callSid }); } }); ``` ### `endCall` [Section titled “endCall”](#endcall) End an active call. If callSid is not provided, this will end the currently active call. ```typescript import { CapacitorTwilioVoice } from '@capgo/capacitor-twilio-voice'; // End the current active call await CapacitorTwilioVoice.endCall({}); // End a specific call await CapacitorTwilioVoice.endCall({ callSid: 'CA1234567890abcdef' }); ``` ### `muteCall` [Section titled “muteCall”](#mutecall) Mute or unmute the microphone during an active call. When muted, the other party will not hear audio from your microphone. ```typescript import { CapacitorTwilioVoice } from '@capgo/capacitor-twilio-voice'; // Mute the microphone await CapacitorTwilioVoice.muteCall({ muted: true }); // Unmute the microphone await CapacitorTwilioVoice.muteCall({ muted: false }); ``` ### `setSpeaker` [Section titled “setSpeaker”](#setspeaker) Enable or disable speakerphone mode. When enabled, audio will be routed through the device’s speaker instead of the earpiece. ```typescript import { CapacitorTwilioVoice } from '@capgo/capacitor-twilio-voice'; // Enable speakerphone await CapacitorTwilioVoice.setSpeaker({ enabled: true }); // Disable speakerphone await CapacitorTwilioVoice.setSpeaker({ enabled: false }); ``` ### `getCallStatus` [Section titled “getCallStatus”](#getcallstatus) Get the current status of the active call. This provides real-time information about the call state, mute status, hold status, and call identifiers. ```typescript import { CapacitorTwilioVoice } from '@capgo/capacitor-twilio-voice'; const status = await CapacitorTwilioVoice.getCallStatus(); if (status.hasActiveCall) { console.log('Call SID:', status.callSid); console.log('Call State:', status.callState); console.log('Is Muted:', status.isMuted); console.log('Is On Hold:', status.isOnHold); } ``` ### `checkMicrophonePermission` [Section titled “checkMicrophonePermission”](#checkmicrophonepermission) Check if microphone permission has been granted. This does not request permission, only checks the current permission status. ```typescript import { CapacitorTwilioVoice } from '@capgo/capacitor-twilio-voice'; const result = await CapacitorTwilioVoice.checkMicrophonePermission(); if (!result.granted) { console.log('Microphone permission not granted'); } ``` ### `requestMicrophonePermission` [Section titled “requestMicrophonePermission”](#requestmicrophonepermission) Request microphone permission from the user. On iOS and Android, this will show the system permission dialog if permission has not been granted yet. If permission was previously denied, the user may need to grant it in system settings. ```typescript import { CapacitorTwilioVoice } from '@capgo/capacitor-twilio-voice'; const result = await CapacitorTwilioVoice.requestMicrophonePermission(); if (result.granted) { console.log('Microphone permission granted'); } else { console.log('Microphone permission denied'); } ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `CallInvite` [Section titled “CallInvite”](#callinvite) Capacitor plugin for integrating Twilio Voice functionality into mobile applications. ```typescript export interface CallInvite { /** Unique identifier for the incoming call invitation */ callSid: string; /** Phone number or client identifier of the caller (may include custom caller name) */ from: string; /** Phone number or client identifier being called */ to: string; /** Custom parameters passed with the call invitation */ customParams: Record<string, string>; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-updater > Live update for capacitor apps. ## Overview [Section titled “Overview”](#overview) Live update for capacitor apps. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `notifyAppReady` - Notify the native layer that JavaScript initialized successfully. * `setUpdateUrl` - Set the update URL for the app dynamically at runtime. * `setStatsUrl` - Set the statistics URL for the app dynamically at runtime. * `setChannelUrl` - Set the channel URL for the app dynamically at runtime. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `notifyAppReady` | Notify the native layer that JavaScript initialized successfully. | | `setUpdateUrl` | Set the update URL for the app dynamically at runtime. | | `setStatsUrl` | Set the statistics URL for the app dynamically at runtime. | | `setChannelUrl` | Set the channel URL for the app dynamically at runtime. | | `download` | Download a new bundle from the provided URL for later installation. | | `next` | Set the next bundle to be activated when the app backgrounds or restarts. | | `set` | Set the current bundle and immediately reloads the app. | | `delete` | Delete a bundle from local storage to free up disk space. | | `setBundleError` | Manually mark a bundle as failed/errored in manual update mode. | | `list` | Get all locally downloaded bundles stored in your app. | | `reset` | Reset the app to a known good bundle. | | `current` | Get information about the currently active bundle. | | `reload` | Manually reload the app to apply a pending update. | | `setMultiDelay` | Configure conditions that must be met before a pending update is applied. | | `cancelDelay` | Cancel all delay conditions and apply the pending update immediately. | | `getLatest` | Check the update server for the latest available bundle version. | | `setChannel` | Assign this device to a specific update channel at runtime. | | `unsetChannel` | Remove the device’s channel assignment and return to the default channel. | | `getChannel` | Get the current channel assigned to this device. | | `listChannels` | Get a list of all channels available for this device to self-assign to. | | `setCustomId` | Set a custom identifier for this device. | | `getBuiltinVersion` | Get the builtin bundle version (the original version shipped with your native app). | | `getDeviceId` | Get the unique, privacy-friendly identifier for this device. | | `getPluginVersion` | Get the version of the Capacitor Updater plugin installed in your app. | | `isAutoUpdateEnabled` | Check if automatic updates are currently enabled. | | `removeAllListeners` | Remove all event listeners registered for this plugin. | | `addListener` | Listen for bundle download event in the App. Fires once a download has started, during downloading and when finished. This will return you all download percent during the download. | | `addListener` | Listen for no need to update event, useful when you want force check every time the app is launched. | | `addListener` | Listen for available update event, useful when you want to force check every time the app is launched. | | `addListener` | Listen for downloadComplete events. | | `addListener` | Listen for breaking update events when the backend flags an update as incompatible with the current app. Emits the same payload as the legacy `majorAvailable` listener. | | `addListener` | Listen for Major update event in the App, let you know when major update is blocked by setting disableAutoUpdateBreaking. | | `addListener` | Listen for update fail event in the App, let you know when update has fail to install at next app start. | | `addListener` | Listen for set event in the App, let you know when a bundle has been applied successfully. This event is retained natively until JavaScript consumes it, so if the app reloads before your listener is attached, the last pending `set` event is delivered once the listener subscribes. | | `addListener` | Listen for set next event in the App, let you know when a bundle is queued as the next bundle to install. | | `addListener` | Listen for download fail event in the App, let you know when a bundle download has failed. | | `addListener` | Listen for reload event in the App, let you know when reload has happened. | | `addListener` | Listen for app ready event in the App, let you know when app is ready to use. This event is retained natively until JavaScript consumes it, so it can still be delivered after a reload even if the listener is attached later in app startup. | | `addListener` | Listen for channel private event, fired when attempting to set a channel that doesn’t allow device self-assignment. | | `addListener` | Listen for flexible update state changes on Android. | | `isAutoUpdateAvailable` | Check if the auto-update feature is available (not disabled by custom server configuration). | | `getNextBundle` | Get information about the bundle queued to be activated on next reload. | | `getFailedUpdate` | Retrieve information about the most recent bundle that failed to load. | | `setShakeMenu` | Enable or disable the shake gesture menu for debugging and testing. | | `isShakeMenuEnabled` | Check if the shake gesture debug menu is currently enabled. | | `setShakeChannelSelector` | Enable or disable the shake channel selector at runtime. | | `isShakeChannelSelectorEnabled` | Check if the shake channel selector is currently enabled. | | `getAppId` | Get the currently configured App ID used for update server communication. | | `setAppId` | Dynamically change the App ID used for update server communication. | | `getAppUpdateInfo` | Get information about the app’s availability in the App Store or Play Store. | | `openAppStore` | Open the app’s page in the App Store or Play Store. | | `performImmediateUpdate` | Perform an immediate in-app update on Android. | | `startFlexibleUpdate` | Start a flexible in-app update on Android. | | `completeFlexibleUpdate` | Complete a flexible in-app update on Android. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-updater](https://github.com/Cap-go/capacitor-updater/). # Functions and settings > All available method and settings of the plugin # Updater Plugin Config [Section titled “Updater Plugin Config”](#updater-plugin-config) See the Github [Readme](https://github.com/Cap-go/capacitor-updater) for more information. <!--Update the source file JSDoc comments and rerun docgen to update the docs below--> CapacitorUpdater can be configured with these options: | Prop | Type | Description | Default | Since | | ---------------------------- | -------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------- | ------- | | **`appReadyTimeout`** | `number` | Configure the number of milliseconds the native plugin should wait before considering an update ‘failed’. Available on Android, iOS, and Electron. | `10000 // (10 seconds)` | | | **`responseTimeout`** | `number` | Configure the number of milliseconds the native plugin should wait before considering API timeout. Available on Android, iOS, and Electron. | `20000 // (20 seconds)` | | | **`autoDeleteFailed`** | `boolean` | Configure whether the plugin should use automatically delete failed bundles. Available on Android, iOS, and Electron. | `true` | | | **`autoDeletePrevious`** | `boolean` | Configure whether the plugin should use automatically delete previous bundles after a successful update. Available on Android, iOS, and Electron. | `true` | | | **`autoUpdate`** | `boolean` | Configure whether the plugin should use Auto Update via an update server. Available on Android, iOS, and Electron. | `true` | | | **`resetWhenUpdate`** | `boolean` | Automatically delete previous downloaded bundles when a newer native app bundle is installed to the device. Available on Android, iOS, and Electron. | `true` | | | **`updateUrl`** | `string` | Configure the URL / endpoint to which update checks are sent. Available on Android, iOS, and Electron. | `https://plugin.capgo.app/updates` | | | **`channelUrl`** | `string` | Configure the URL / endpoint for channel operations. Available on Android, iOS, and Electron. | `https://plugin.capgo.app/channel_self` | | | **`statsUrl`** | `string` | Configure the URL / endpoint to which update statistics are sent. Available on Android, iOS, and Electron. Set to "" to disable stats reporting. | `https://plugin.capgo.app/stats` | | | **`publicKey`** | `string` | Configure the public key for end to end live update encryption Version 2. Available on Android, iOS, and Electron. | `undefined` | 6.2.0 | | **`version`** | `string` | Configure the current version of the app. This will be used for the first update request. If not set, the plugin will get the version from the native code. Available on Android, iOS, and Electron. | `undefined` | 4.17.48 | | **`directUpdate`** | `boolean \| ‘always’ \| ‘atInstall’ \| ‘onLaunch’` | Configure when the plugin should direct install updates. Only for autoUpdate mode. Works well for apps less than 10MB and with uploads done using the —delta flag. Zip or apps more than 10MB will be relatively slow for users to update. - false: Never do direct updates (use default behavior: download at start, set when backgrounded) - atInstall: Direct update only when app is installed, updated from store, otherwise act as directUpdate = false - onLaunch: Direct update only on app installed, updated from store or after app kill, otherwise act as directUpdate = false - always: Direct update in all previous cases (app installed, updated from store, after app kill or app resume), never act as directUpdate = false - true: (deprecated) Same as “always” for backward compatibility Available on Android, iOS, and Electron. | `false` | 5.1.0 | | **`autoSplashscreen`** | `boolean` | Automatically handle splashscreen hiding when using directUpdate. When enabled, the plugin will automatically hide the splashscreen after updates are applied or when no update is needed. This removes the need to manually listen for appReady events and call SplashScreen.hide(). Only works when directUpdate is set to “atInstall”, “always”, or true. Requires the @capacitor/splash-screen plugin to be installed and configured with launchAutoHide: false. Requires autoUpdate and directUpdate to be enabled. Available on Android and iOS. | `false` | 7.6.0 | | **`periodCheckDelay`** | `number` | Configure the delay period for period update check. the unit is in seconds. Available on Android, iOS, and Electron. Cannot be less than 600 seconds (10 minutes). | `600 // (10 minutes)` | | | **`localS3`** | `boolean` | Configure the CLI to use a local server for testing or self-hosted update server. | `undefined` | 4.17.48 | | **`localHost`** | `string` | Configure the CLI to use a local server for testing or self-hosted update server. | `undefined` | 4.17.48 | | **`localWebHost`** | `string` | Configure the CLI to use a local server for testing or self-hosted update server. | `undefined` | 4.17.48 | | **`localSupa`** | `string` | Configure the CLI to use a local server for testing or self-hosted update server. | `undefined` | 4.17.48 | | **`localSupaAnon`** | `string` | Configure the CLI to use a local server for testing. | `undefined` | 4.17.48 | | **`localApi`** | `string` | Configure the CLI to use a local api for testing. | `undefined` | 6.3.3 | | **`localApiFiles`** | `string` | Configure the CLI to use a local file api for testing. | `undefined` | 6.3.3 | | **`allowModifyUrl`** | `boolean` | Allow the plugin to modify the updateUrl, statsUrl and channelUrl dynamically from the JavaScript side. | `false` | 5.4.0 | | **`defaultChannel`** | `string` | Set the default channel for the app in the config. Case sensitive. This will setting will override the default channel set in the cloud, but will still respect overrides made in the cloud. | `undefined` | 5.5.0 | | **`appId`** | `string` | Configure the app id for the app in the config. | `undefined` | 6.0.0 | | **`keepUrlPathAfterReload`** | `boolean` | Configure the plugin to keep the URL path after a reload. WARNING: When a reload is triggered, ‘window\.history’ will be cleared. | `false` | 6.8.0 | | **`disableJSLogging`** | `boolean` | Disable the JavaScript logging of the plugin. if true, the plugin will not log to the JavaScript console. only the native log will be done | `false` | 7.3.0 | | **`shakeMenu`** | `boolean` | Enable shake gesture to show update menu for debugging/testing purposes | `false` | 7.5.0 | ## Examples [Section titled “Examples”](#examples) In `capacitor.config.json`: ```json { "plugins": { "CapacitorUpdater": { "appReadyTimeout": 1000 // (1 second), "responseTimeout": 10 // (10 second), "autoDeleteFailed": false, "autoDeletePrevious": false, "autoUpdate": false, "resetWhenUpdate": false, "updateUrl": https://example.com/api/auto_update, "channelUrl": https://example.com/api/channel, "statsUrl": https://example.com/api/stats, "publicKey": undefined, "version": undefined, "directUpdate": undefined, "autoSplashscreen": undefined, "periodCheckDelay": undefined, "localS3": undefined, "localHost": undefined, "localWebHost": undefined, "localSupa": undefined, "localSupaAnon": undefined, "localApi": undefined, "localApiFiles": undefined, "allowModifyUrl": undefined, "defaultChannel": undefined, "appId": undefined, "keepUrlPathAfterReload": undefined, "disableJSLogging": undefined, "shakeMenu": undefined } } } ``` In `capacitor.config.ts`: ```ts import { CapacitorConfig } from '@capacitor/cli'; const config: CapacitorConfig = { plugins: { CapacitorUpdater: { appReadyTimeout: 1000 // (1 second), responseTimeout: 10 // (10 second), autoDeleteFailed: false, autoDeletePrevious: false, autoUpdate: false, resetWhenUpdate: false, updateUrl: https://example.com/api/auto_update, channelUrl: https://example.com/api/channel, statsUrl: https://example.com/api/stats, publicKey: undefined, version: undefined, directUpdate: undefined, autoSplashscreen: undefined, periodCheckDelay: undefined, localS3: undefined, localHost: undefined, localWebHost: undefined, localSupa: undefined, localSupaAnon: undefined, localApi: undefined, localApiFiles: undefined, allowModifyUrl: undefined, defaultChannel: undefined, appId: undefined, keepUrlPathAfterReload: undefined, disableJSLogging: undefined, shakeMenu: undefined, }, }, }; export default config; ``` * [`notifyAppReady()`](#notifyappready) * [`setUpdateUrl(...)`](#setupdateurl) * [`setStatsUrl(...)`](#setstatsurl) * [`setChannelUrl(...)`](#setchannelurl) * [`download(...)`](#download) * [`next(...)`](#next) * [`set(...)`](#set) * [`delete(...)`](#delete) * [`list(...)`](#list) * [`reset(...)`](#reset) * [`current()`](#current) * [`reload()`](#reload) * [`setMultiDelay(...)`](#setmultidelay) * [`cancelDelay()`](#canceldelay) * [`getLatest(...)`](#getlatest) * [`setChannel(...)`](#setchannel) * [`unsetChannel(...)`](#unsetchannel) * [`getChannel()`](#getchannel) * [`listChannels()`](#listchannels) * [`setCustomId(...)`](#setcustomid) * [`getBuiltinVersion()`](#getbuiltinversion) * [`getDeviceId()`](#getdeviceid) * [`getPluginVersion()`](#getpluginversion) * [`isAutoUpdateEnabled()`](#isautoupdateenabled) * [`removeAllListeners()`](#removealllisteners) * [`addListener('download', ...)`](#addlistenerdownload-) * [`addListener('noNeedUpdate', ...)`](#addlistenernoneedupdate-) * [`addListener('updateAvailable', ...)`](#addlistenerupdateavailable-) * [`addListener('downloadComplete', ...)`](#addlistenerdownloadcomplete-) * [`addListener('majorAvailable', ...)`](#addlistenermajoravailable-) * [`addListener('updateFailed', ...)`](#addlistenerupdatefailed-) * [`addListener('downloadFailed', ...)`](#addlistenerdownloadfailed-) * [`addListener('appReloaded', ...)`](#addlistenerappreloaded-) * [`addListener('appReady', ...)`](#addlistenerappready-) * [`isAutoUpdateAvailable()`](#isautoupdateavailable) * [`getNextBundle()`](#getnextbundle) * [`setShakeMenu(...)`](#setshakemenu) * [`isShakeMenuEnabled()`](#isshakemenuenabled) * [Interfaces](#interfaces) * [Type Aliases](#type-aliases) # Methods [Section titled “Methods”](#methods) <!--Update the source file JSDoc comments and rerun docgen to update the docs below--> ## notifyAppReady() [Section titled “notifyAppReady()”](#notifyappready) ```typescript notifyAppReady() => Promise<AppReadyResult> ``` Notify Capacitor Updater that the current bundle is working (a rollback will occur if this method is not called on every app launch) By default this method should be called in the first 10 sec after app launch, otherwise a rollback will occur. Change this behaviour with {@link appReadyTimeout} **Returns:** `Promise<AppReadyResult>` *** ## setUpdateUrl(…) [Section titled “setUpdateUrl(…)”](#setupdateurl) ```typescript setUpdateUrl(options: UpdateUrl) => Promise<void> ``` Set the updateUrl for the app, this will be used to check for updates. | Param | Type | Description | | ------------- | ----------- | ------------------------------------------------- | | **`options`** | `UpdateUrl` | contains the URL to use for checking for updates. | **Since:** 5.4.0 *** ## setStatsUrl(…) [Section titled “setStatsUrl(…)”](#setstatsurl) ```typescript setStatsUrl(options: StatsUrl) => Promise<void> ``` Set the statsUrl for the app, this will be used to send statistics. Passing an empty string will disable statistics gathering. | Param | Type | Description | | ------------- | ---------- | ----------------------------------------------- | | **`options`** | `StatsUrl` | contains the URL to use for sending statistics. | **Since:** 5.4.0 *** ## setChannelUrl(…) [Section titled “setChannelUrl(…)”](#setchannelurl) ```typescript setChannelUrl(options: ChannelUrl) => Promise<void> ``` Set the channelUrl for the app, this will be used to set the channel. | Param | Type | Description | | ------------- | ------------ | ------------------------------------------------ | | **`options`** | `ChannelUrl` | contains the URL to use for setting the channel. | **Since:** 5.4.0 *** ## download(…) [Section titled “download(…)”](#download) ```typescript download(options: DownloadOptions) => Promise<BundleInfo> ``` Download a new bundle from the provided URL, it should be a zip file, with files inside or with a unique id inside with all your files | Param | Type | Description | | ------------- | ----------------- | --------------------------------------------------------------------------------- | | **`options`** | `DownloadOptions` | The {@link [DownloadOptions](#downloadoptions)} for downloading a new bundle zip. | **Returns:** `Promise<BundleInfo>` *** ## next(…) [Section titled “next(…)”](#next) ```typescript next(options: BundleId) => Promise<BundleInfo> ``` Set the next bundle to be used when the app is reloaded. | Param | Type | Description | | ------------- | ---------- | -------------------------------------------------------------------------------------------------- | | **`options`** | `BundleId` | Contains the ID of the next Bundle to set on next app launch. {@link [BundleInfo.id](#bundleinfo)} | **Returns:** `Promise<BundleInfo>` *** ## set(…) [Section titled “set(…)”](#set) ```typescript set(options: BundleId) => Promise<void> ``` Set the current bundle and immediately reloads the app. | Param | Type | Description | | ------------- | ---------- | -------------------------------------------------------------------------------------- | | **`options`** | `BundleId` | A {@link [BundleId](#bundleid)} object containing the new bundle id to set as current. | *** ## delete(…) [Section titled “delete(…)”](#delete) ```typescript delete(options: BundleId) => Promise<void> ``` Deletes the specified bundle from the native app storage. Use with {@link list} to get the stored Bundle IDs. | Param | Type | Description | | ------------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------- | | **`options`** | `BundleId` | A {@link [BundleId](#bundleid)} object containing the ID of a bundle to delete (note, this is the bundle id, NOT the version name) | *** ## list(…) [Section titled “list(…)”](#list) ```typescript list(options?: ListOptions | undefined) => Promise<BundleListResult> ``` Get all locally downloaded bundles in your app | Param | Type | Description | | ------------- | ------------- | ----------------------------------------------------------- | | **`options`** | `ListOptions` | The {@link [ListOptions](#listoptions)} for listing bundles | **Returns:** `Promise<BundleListResult>` *** ## reset(…) [Section titled “reset(…)”](#reset) ```typescript reset(options?: ResetOptions | undefined) => Promise<void> ``` Reset the app to the `builtin` bundle (the one sent to Apple App Store / Google Play Store ) or the last successfully loaded bundle. | Param | Type | Description | | ------------- | -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **`options`** | `ResetOptions` | Containing {@link [ResetOptions.toLastSuccessful](#resetoptions)}, `true` resets to the builtin bundle and `false` will reset to the last successfully loaded bundle. | *** ## current() [Section titled “current()”](#current) ```typescript current() => Promise<CurrentBundleResult> ``` Get the current bundle, if none are set it returns `builtin`. currentNative is the original bundle installed on the device **Returns:** `Promise<CurrentBundleResult>` *** ## reload() [Section titled “reload()”](#reload) ```typescript reload() => Promise<void> ``` Reload the view *** ## setMultiDelay(…) [Section titled “setMultiDelay(…)”](#setmultidelay) ```typescript setMultiDelay(options: MultiDelayConditions) => Promise<void> ``` Sets a {@link [DelayCondition](#delaycondition)} array containing conditions that the Plugin will use to delay the update. After all conditions are met, the update process will run start again as usual, so update will be installed after a backgrounding or killing the app. For the `date` kind, the value should be an iso8601 date string. For the `background` kind, the value should be a number in milliseconds. For the `nativeVersion` kind, the value should be the version number. For the `kill` kind, the value is not used. The function has inconsistent behavior the option kill do trigger the update after the first kill and not after the next background like other options. This will be fixed in a future major release. | Param | Type | Description | | ------------- | ---------------------- | ----------------------------------------------------------------------------------------------- | | **`options`** | `MultiDelayConditions` | Containing the {@link [MultiDelayConditions](#multidelayconditions)} array of conditions to set | **Since:** 4.3.0 *** ## cancelDelay() [Section titled “cancelDelay()”](#canceldelay) ```typescript cancelDelay() => Promise<void> ``` Cancels a {@link [DelayCondition](#delaycondition)} to process an update immediately. **Since:** 4.0.0 *** ## getLatest(…) [Section titled “getLatest(…)”](#getlatest) ```typescript getLatest(options?: GetLatestOptions | undefined) => Promise<LatestVersion> ``` Get Latest bundle available from update Url | Param | Type | | ------------- | ------------------ | | **`options`** | `GetLatestOptions` | **Returns:** `Promise<LatestVersion>` **Since:** 4.0.0 *** ## setChannel(…) [Section titled “setChannel(…)”](#setchannel) ```typescript setChannel(options: SetChannelOptions) => Promise<ChannelRes> ``` Sets the channel for this device. The channel must have `allow_device_self_set` enabled for this to work. **Important notes:** * Do not use this method to set the channel at boot. Use the `defaultChannel` in your Capacitor config instead. * This method is intended for use after the app is ready and the user has interacted (e.g., opting into a beta program). * **Public channels cannot be self-assigned.** If a channel is marked as `public`, calling `setChannel()` will return an error. To use a public channel, call `unsetChannel()` instead - the device will automatically fall back to the matching public channel. * Use `listChannels()` to discover which channels are available and whether they allow self-assignment. | Param | Type | Description | | ------------- | ------------------- | --------------------------------------------------------------------- | | **`options`** | `SetChannelOptions` | Is the {@link [SetChannelOptions](#setchanneloptions)} channel to set | **Returns:** `Promise<ChannelRes>` **Since:** 4.7.0 *** ## unsetChannel(…) [Section titled “unsetChannel(…)”](#unsetchannel) ```typescript unsetChannel(options: UnsetChannelOptions) => Promise<void> ``` Unset the channel override for this device. After calling this method, the device will automatically receive updates from the **public channel** that matches its conditions (platform, device type, build type). This is useful when: * You want to move a device back to the default update track * You want to use a public channel (since public channels cannot be self-assigned via `setChannel()`) | Param | Type | | ------------- | --------------------- | | **`options`** | `UnsetChannelOptions` | **Since:** 4.7.0 *** ## getChannel() [Section titled “getChannel()”](#getchannel) ```typescript getChannel() => Promise<GetChannelRes> ``` Get the channel for this device **Returns:** `Promise<GetChannelRes>` **Since:** 4.8.0 *** ## listChannels() [Section titled “listChannels()”](#listchannels) ```typescript listChannels() => Promise<ListChannelsResult> ``` List all channels available for this device. Returns channels that are compatible with the device’s current environment (platform, emulator/real device, dev/prod build) and are either public or allow self-assignment. Each channel in the result includes: * `public`: If `true`, this is a **default channel**. You cannot self-assign to it using `setChannel()`. Instead, if you remove your channel assignment using `unsetChannel()`, the device will automatically receive updates from this public channel. * `allow_self_set`: If `true`, this is a **self-assignable channel**. You can explicitly assign the device to this channel using `setChannel()`. **Returns:** `Promise<ListChannelsResult>` **Since:** 7.5.0 *** ## setCustomId(…) [Section titled “setCustomId(…)”](#setcustomid) ```typescript setCustomId(options: SetCustomIdOptions) => Promise<void> ``` Set a custom ID for this device | Param | Type | Description | | ------------- | -------------------- | ------------------------------------------------------------------------ | | **`options`** | `SetCustomIdOptions` | is the {@link [SetCustomIdOptions](#setcustomidoptions)} customId to set | **Since:** 4.9.0 *** ## getBuiltinVersion() [Section titled “getBuiltinVersion()”](#getbuiltinversion) ```typescript getBuiltinVersion() => Promise<BuiltinVersion> ``` Get the native app version or the builtin version if set in config **Returns:** `Promise<BuiltinVersion>` **Since:** 5.2.0 *** ## getDeviceId() [Section titled “getDeviceId()”](#getdeviceid) ```typescript getDeviceId() => Promise<DeviceId> ``` Get unique ID used to identify device (sent to auto update server) **Returns:** `Promise<DeviceId>` *** ## getPluginVersion() [Section titled “getPluginVersion()”](#getpluginversion) ```typescript getPluginVersion() => Promise<PluginVersion> ``` Get the native Capacitor Updater plugin version (sent to auto update server) **Returns:** `Promise<PluginVersion>` *** ## isAutoUpdateEnabled() [Section titled “isAutoUpdateEnabled()”](#isautoupdateenabled) ```typescript isAutoUpdateEnabled() => Promise<AutoUpdateEnabled> ``` Get the state of auto update config. **Returns:** `Promise<AutoUpdateEnabled>` *** ## removeAllListeners() [Section titled “removeAllListeners()”](#removealllisteners) ```typescript removeAllListeners() => Promise<void> ``` Remove all listeners for this plugin. **Since:** 1.0.0 *** ## addListener(‘download’, …) [Section titled “addListener(‘download’, …)”](#addlistenerdownload-) ```typescript addListener(eventName: 'download', listenerFunc: (state: DownloadEvent) => void) => Promise<PluginListenerHandle> ``` Listen for bundle download event in the App. Fires once a download has started, during downloading and when finished. This will return you all download percent during the download | Param | Type | | ------------------ | -------------------------------- | | **`eventName`** | `’download’` | | **`listenerFunc`** | `(state: DownloadEvent) => void` | **Returns:** `Promise<PluginListenerHandle>` **Since:** 2.0.11 *** ## addListener(‘noNeedUpdate’, …) [Section titled “addListener(‘noNeedUpdate’, …)”](#addlistenernoneedupdate-) ```typescript addListener(eventName: 'noNeedUpdate', listenerFunc: (state: NoNeedEvent) => void) => Promise<PluginListenerHandle> ``` Listen for no need to update event, useful when you want force check every time the app is launched | Param | Type | | ------------------ | ------------------------------ | | **`eventName`** | `’noNeedUpdate’` | | **`listenerFunc`** | `(state: NoNeedEvent) => void` | **Returns:** `Promise<PluginListenerHandle>` **Since:** 4.0.0 *** ## addListener(‘updateAvailable’, …) [Section titled “addListener(‘updateAvailable’, …)”](#addlistenerupdateavailable-) ```typescript addListener(eventName: 'updateAvailable', listenerFunc: (state: UpdateAvailableEvent) => void) => Promise<PluginListenerHandle> ``` Listen for available update event, useful when you want to force check every time the app is launched | Param | Type | | ------------------ | --------------------------------------- | | **`eventName`** | `’updateAvailable’` | | **`listenerFunc`** | `(state: UpdateAvailableEvent) => void` | **Returns:** `Promise<PluginListenerHandle>` **Since:** 4.0.0 *** ## addListener(‘downloadComplete’, …) [Section titled “addListener(‘downloadComplete’, …)”](#addlistenerdownloadcomplete-) ```typescript addListener(eventName: 'downloadComplete', listenerFunc: (state: DownloadCompleteEvent) => void) => Promise<PluginListenerHandle> ``` Listen for downloadComplete events. | Param | Type | | ------------------ | ---------------------------------------- | | **`eventName`** | `’downloadComplete’` | | **`listenerFunc`** | `(state: DownloadCompleteEvent) => void` | **Returns:** `Promise<PluginListenerHandle>` **Since:** 4.0.0 *** ## addListener(‘majorAvailable’, …) [Section titled “addListener(‘majorAvailable’, …)”](#addlistenermajoravailable-) ```typescript addListener(eventName: 'majorAvailable', listenerFunc: (state: MajorAvailableEvent) => void) => Promise<PluginListenerHandle> ``` Listen for Major update event in the App, let you know when major update is blocked by setting disableAutoUpdateBreaking | Param | Type | | ------------------ | -------------------------------------- | | **`eventName`** | `’majorAvailable’` | | **`listenerFunc`** | `(state: MajorAvailableEvent) => void` | **Returns:** `Promise<PluginListenerHandle>` **Since:** 2.3.0 *** ## addListener(‘updateFailed’, …) [Section titled “addListener(‘updateFailed’, …)”](#addlistenerupdatefailed-) ```typescript addListener(eventName: 'updateFailed', listenerFunc: (state: UpdateFailedEvent) => void) => Promise<PluginListenerHandle> ``` Listen for update fail event in the App, let you know when update has fail to install at next app start | Param | Type | | ------------------ | ------------------------------------ | | **`eventName`** | `’updateFailed’` | | **`listenerFunc`** | `(state: UpdateFailedEvent) => void` | **Returns:** `Promise<PluginListenerHandle>` **Since:** 2.3.0 *** ## addListener(‘downloadFailed’, …) [Section titled “addListener(‘downloadFailed’, …)”](#addlistenerdownloadfailed-) ```typescript addListener(eventName: 'downloadFailed', listenerFunc: (state: DownloadFailedEvent) => void) => Promise<PluginListenerHandle> ``` Listen for download fail event in the App, let you know when a bundle download has failed | Param | Type | | ------------------ | -------------------------------------- | | **`eventName`** | `’downloadFailed’` | | **`listenerFunc`** | `(state: DownloadFailedEvent) => void` | **Returns:** `Promise<PluginListenerHandle>` **Since:** 4.0.0 *** ## addListener(‘appReloaded’, …) [Section titled “addListener(‘appReloaded’, …)”](#addlistenerappreloaded-) ```typescript addListener(eventName: 'appReloaded', listenerFunc: () => void) => Promise<PluginListenerHandle> ``` Listen for reload event in the App, let you know when reload has happened | Param | Type | | ------------------ | --------------- | | **`eventName`** | `’appReloaded’` | | **`listenerFunc`** | `() => void` | **Returns:** `Promise<PluginListenerHandle>` **Since:** 4.3.0 *** ## addListener(‘appReady’, …) [Section titled “addListener(‘appReady’, …)”](#addlistenerappready-) ```typescript addListener(eventName: 'appReady', listenerFunc: (state: AppReadyEvent) => void) => Promise<PluginListenerHandle> ``` Listen for app ready event in the App, let you know when app is ready to use | Param | Type | | ------------------ | -------------------------------- | | **`eventName`** | `’appReady’` | | **`listenerFunc`** | `(state: AppReadyEvent) => void` | **Returns:** `Promise<PluginListenerHandle>` **Since:** 5.1.0 *** ## isAutoUpdateAvailable() [Section titled “isAutoUpdateAvailable()”](#isautoupdateavailable) ```typescript isAutoUpdateAvailable() => Promise<AutoUpdateAvailable> ``` Get if auto update is available (not disabled by serverUrl). **Returns:** `Promise<AutoUpdateAvailable>` *** ## getNextBundle() [Section titled “getNextBundle()”](#getnextbundle) ```typescript getNextBundle() => Promise<BundleInfo | null> ``` Get the next bundle that will be used when the app reloads. Returns null if no next bundle is set. **Returns:** `Promise<BundleInfo | null>` **Since:** 6.8.0 *** ## setShakeMenu(…) [Section titled “setShakeMenu(…)”](#setshakemenu) ```typescript setShakeMenu(options: SetShakeMenuOptions) => Promise<void> ``` Enable or disable the shake menu for debugging/testing purposes | Param | Type | Description | | ------------- | --------------------- | -------------------------------------------------------- | | **`options`** | `SetShakeMenuOptions` | Contains enabled boolean to enable or disable shake menu | **Since:** 7.5.0 *** ## isShakeMenuEnabled() [Section titled “isShakeMenuEnabled()”](#isshakemenuenabled) ```typescript isShakeMenuEnabled() => Promise<ShakeMenuEnabled> ``` Get the current state of the shake menu **Returns:** `Promise<ShakeMenuEnabled>` **Since:** 7.5.0 *** ## Interfaces [Section titled “Interfaces”](#interfaces) ### AppReadyResult [Section titled “AppReadyResult”](#appreadyresult) | Prop | Type | | ------------ | ------------ | | **`bundle`** | `BundleInfo` | ### BundleInfo [Section titled “BundleInfo”](#bundleinfo) | Prop | Type | | ---------------- | -------------- | | **`id`** | `string` | | **`version`** | `string` | | **`downloaded`** | `string` | | **`checksum`** | `string` | | **`status`** | `BundleStatus` | ### UpdateUrl [Section titled “UpdateUrl”](#updateurl) | Prop | Type | | --------- | -------- | | **`url`** | `string` | ### StatsUrl [Section titled “StatsUrl”](#statsurl) | Prop | Type | | --------- | -------- | | **`url`** | `string` | ### ChannelUrl [Section titled “ChannelUrl”](#channelurl) | Prop | Type | | --------- | -------- | | **`url`** | `string` | ### DownloadOptions [Section titled “DownloadOptions”](#downloadoptions) This URL and versions are used to download the bundle from the server, If you use backend all information will be given by the method getLatest. If you don’t use backend, you need to provide the URL and version of the bundle. SessionKey are required if you encrypted the bundle with the CLI command encrypt, you should receive them as result of the command. | Prop | Type | Description | Default | Since | | ---------------- | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- | ----- | | **`url`** | `string` | The URL of the bundle zip file (e.g: dist.zip) to be downloaded. (This can be any URL. E.g: Amazon S3, a GitHub tag, any other place you’ve hosted your bundle.) | | | | **`version`** | `string` | The version code/name of this bundle/version | | | | **`sessionKey`** | `string` | The session key for the update, when the bundle is encrypted with a session key | `undefined` | 4.0.0 | | **`checksum`** | `string` | The checksum for the update, it should be in sha256 and encrypted with private key if the bundle is encrypted | `undefined` | 4.0.0 | | **`manifest`** | `ManifestEntry[]` | The manifest for Delta (manifest) multi-file downloads | `undefined` | 6.1.0 | ### ManifestEntry [Section titled “ManifestEntry”](#manifestentry) | Prop | Type | | ------------------ | ---------------- | | **`file_name`** | `string \| null` | | **`file_hash`** | `string \| null` | | **`download_url`** | `string \| null` | ### BundleId [Section titled “BundleId”](#bundleid) | Prop | Type | | -------- | -------- | | **`id`** | `string` | ### BundleListResult [Section titled “BundleListResult”](#bundlelistresult) | Prop | Type | | ------------- | -------------- | | **`bundles`** | `BundleInfo[]` | ### ListOptions [Section titled “ListOptions”](#listoptions) | Prop | Type | Description | Default | Since | | --------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------- | ------- | ------ | | **`raw`** | `boolean` | Whether to return the raw bundle list or the manifest. If true, the list will attempt to read the internal database instead of files on disk. | `false` | 6.14.0 | ### ResetOptions [Section titled “ResetOptions”](#resetoptions) | Prop | Type | | ---------------------- | --------- | | **`toLastSuccessful`** | `boolean` | ### CurrentBundleResult [Section titled “CurrentBundleResult”](#currentbundleresult) | Prop | Type | | ------------ | ------------ | | **`bundle`** | `BundleInfo` | | **`native`** | `string` | ### MultiDelayConditions [Section titled “MultiDelayConditions”](#multidelayconditions) | Prop | Type | | --------------------- | ------------------ | | **`delayConditions`** | `DelayCondition[]` | ### DelayCondition [Section titled “DelayCondition”](#delaycondition) | Prop | Type | Description | | ----------- | ---------------- | ---------------------------------------- | | **`kind`** | `DelayUntilNext` | Set up delay conditions in setMultiDelay | | **`value`** | `string` | | ### LatestVersion [Section titled “LatestVersion”](#latestversion) | Prop | Type | Description | Since | | ---------------- | ----------------- | -------------------------- | ----- | | **`version`** | `string` | Result of getLatest method | 4.0.0 | | **`checksum`** | `string` | | 6 | | **`major`** | `boolean` | | | | **`message`** | `string` | | | | **`sessionKey`** | `string` | | | | **`error`** | `string` | | | | **`old`** | `string` | | | | **`url`** | `string` | | | | **`manifest`** | `ManifestEntry[]` | | 6.1 | ### GetLatestOptions [Section titled “GetLatestOptions”](#getlatestoptions) | Prop | Type | Description | Default | Since | | ------------- | -------- | ------------------------------------------------------------------------------------------------ | ----------- | ----- | | **`channel`** | `string` | The channel to get the latest version for The channel must allow ‘self\_assign’ for this to work | `undefined` | 6.8.0 | ### ChannelRes [Section titled “ChannelRes”](#channelres) | Prop | Type | Description | Since | | ------------- | -------- | ----------------------------- | ----- | | **`status`** | `string` | Current status of set channel | 4.7.0 | | **`error`** | `string` | | | | **`message`** | `string` | | | ### SetChannelOptions [Section titled “SetChannelOptions”](#setchanneloptions) | Prop | Type | | ----------------------- | --------- | | **`channel`** | `string` | | **`triggerAutoUpdate`** | `boolean` | ### UnsetChannelOptions [Section titled “UnsetChannelOptions”](#unsetchanneloptions) | Prop | Type | | ----------------------- | --------- | | **`triggerAutoUpdate`** | `boolean` | ### GetChannelRes [Section titled “GetChannelRes”](#getchannelres) | Prop | Type | Description | Since | | -------------- | --------- | ----------------------------- | ----- | | **`channel`** | `string` | Current status of get channel | 4.8.0 | | **`error`** | `string` | | | | **`message`** | `string` | | | | **`status`** | `string` | | | | **`allowSet`** | `boolean` | | | ### ListChannelsResult [Section titled “ListChannelsResult”](#listchannelsresult) | Prop | Type | Description | Since | | -------------- | --------------- | -------------------------- | ----- | | **`channels`** | `ChannelInfo[]` | List of available channels | 7.5.0 | ### ChannelInfo [Section titled “ChannelInfo”](#channelinfo) | Prop | Type | Description | Since | | -------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----- | | **`id`** | `string` | The channel ID | 7.5.0 | | **`name`** | `string` | The channel name | 7.5.0 | | **`public`** | `boolean` | If true, this is a default/fallback channel. Devices cannot self-assign to public channels. Instead, when a device removes its channel override (using `unsetChannel()`), it will automatically receive updates from the matching public channel. | 7.5.0 | | **`allow_self_set`** | `boolean` | If true, devices can explicitly self-assign to this channel using `setChannel()`. This is typically used for beta testing, A/B testing, or opt-in update tracks. | 7.5.0 | ### SetCustomIdOptions [Section titled “SetCustomIdOptions”](#setcustomidoptions) | Prop | Type | | -------------- | -------- | | **`customId`** | `string` | ### BuiltinVersion [Section titled “BuiltinVersion”](#builtinversion) | Prop | Type | | ------------- | -------- | | **`version`** | `string` | ### DeviceId [Section titled “DeviceId”](#deviceid) | Prop | Type | | -------------- | -------- | | **`deviceId`** | `string` | ### PluginVersion [Section titled “PluginVersion”](#pluginversion) | Prop | Type | | ------------- | -------- | | **`version`** | `string` | ### AutoUpdateEnabled [Section titled “AutoUpdateEnabled”](#autoupdateenabled) | Prop | Type | | ------------- | --------- | | **`enabled`** | `boolean` | ### PluginListenerHandle [Section titled “PluginListenerHandle”](#pluginlistenerhandle) | Prop | Type | | ------------ | --------------------- | | **`remove`** | `() => Promise<void>` | ### DownloadEvent [Section titled “DownloadEvent”](#downloadevent) | Prop | Type | Description | Since | | ------------- | ------------ | ---------------------------------------------- | ----- | | **`percent`** | `number` | Current status of download, between 0 and 100. | 4.0.0 | | **`bundle`** | `BundleInfo` | | | ### NoNeedEvent [Section titled “NoNeedEvent”](#noneedevent) | Prop | Type | Description | Since | | ------------ | ------------ | ---------------------------------------------- | ----- | | **`bundle`** | `BundleInfo` | Current status of download, between 0 and 100. | 4.0.0 | ### UpdateAvailableEvent [Section titled “UpdateAvailableEvent”](#updateavailableevent) | Prop | Type | Description | Since | | ------------ | ------------ | ---------------------------------------------- | ----- | | **`bundle`** | `BundleInfo` | Current status of download, between 0 and 100. | 4.0.0 | ### DownloadCompleteEvent [Section titled “DownloadCompleteEvent”](#downloadcompleteevent) | Prop | Type | Description | Since | | ------------ | ------------ | ------------------------------------ | ----- | | **`bundle`** | `BundleInfo` | Emit when a new update is available. | 4.0.0 | ### MajorAvailableEvent [Section titled “MajorAvailableEvent”](#majoravailableevent) | Prop | Type | Description | Since | | ------------- | -------- | ------------------------------------------ | ----- | | **`version`** | `string` | Emit when a new major bundle is available. | 4.0.0 | ### UpdateFailedEvent [Section titled “UpdateFailedEvent”](#updatefailedevent) | Prop | Type | Description | Since | | ------------ | ------------ | ------------------------------------- | ----- | | **`bundle`** | `BundleInfo` | Emit when a update failed to install. | 4.0.0 | ### DownloadFailedEvent [Section titled “DownloadFailedEvent”](#downloadfailedevent) | Prop | Type | Description | Since | | ------------- | -------- | -------------------------- | ----- | | **`version`** | `string` | Emit when a download fail. | 4.0.0 | ### AppReadyEvent [Section titled “AppReadyEvent”](#appreadyevent) | Prop | Type | Description | Since | | ------------ | ------------ | ------------------------------------- | ----- | | **`bundle`** | `BundleInfo` | Emitted when the app is ready to use. | 5.2.0 | | **`status`** | `string` | | | ### AutoUpdateAvailable [Section titled “AutoUpdateAvailable”](#autoupdateavailable) | Prop | Type | | --------------- | --------- | | **`available`** | `boolean` | ### SetShakeMenuOptions [Section titled “SetShakeMenuOptions”](#setshakemenuoptions) | Prop | Type | | ------------- | --------- | | **`enabled`** | `boolean` | ### ShakeMenuEnabled [Section titled “ShakeMenuEnabled”](#shakemenuenabled) | Prop | Type | | ------------- | --------- | | **`enabled`** | `boolean` | ## Type Aliases [Section titled “Type Aliases”](#type-aliases) ### BundleStatus [Section titled “BundleStatus”](#bundlestatus) pending: The bundle is pending to be **SET** as the next bundle. downloading: The bundle is being downloaded. success: The bundle has been downloaded and is ready to be **SET** as the next bundle. error: The bundle has failed to download. `‘success’ | ‘error’ | ‘pending’ | ‘downloading’` ### DelayUntilNext [Section titled “DelayUntilNext”](#delayuntilnext) `‘background’ | ‘kill’ | ‘nativeVersion’ | ‘date’` # Common Update Problems > Understand common Capgo live-update failure codes, what causes them, and how to fix them quickly. When an update check fails, Capgo usually returns an `error` code and a `message` in the `/updates` response. This page explains the most common failures and the fastest fixes. ## Read this first [Section titled “Read this first”](#read-this-first) * `no_new_version_available` is a normal state, not a failure. * Many “update found but not applied” reports are policy/configuration refusals rather than cache lag, especially when the response includes an explicit `error` code. * Use `npx @capgo/cli@latest app debug` while reproducing the issue to see request/response details. ## Common failure codes [Section titled “Common failure codes”](#common-failure-codes) ### `disable_auto_update_to_major` [Section titled “disable\_auto\_update\_to\_major”](#disable_auto_update_to_major) **Cause** Your channel blocks major upgrades (`disable_auto_update = major`) and the target bundle major is above the device baseline version. **Typical symptom** `version: 1.0.8` with `old: 0.0.0` means the device reports baseline `0.0.0`, so major upgrades are rejected. **How to interpret it** The backend compares major versions using device baseline `old` and target `version`. * If target is `1.0.1`, baseline major must be `1` (for example `1.0.0`). * If target is `10.0.1`, baseline major must be `10` (for example `10.0.0`). **Fix option A (recommended): align device baseline major** Set `plugins.CapacitorUpdater.version` in `capacitor.config.*` so its **MAJOR** matches the bundle MAJOR you want to deliver (for example `1.0.0` for `1.0.1`, `10.0.0` for `10.0.1`). Then apply this config to the installed app once: 1. Run `npx cap sync`. 2. Rebuild and reinstall the native app. **Fix option B: relax channel policy** Allow cross-major auto-updates in channel settings (only if that rollout strategy is intentional). Related docs: * [Version Targeting: Disable Auto-Update Across Major Versions](/docs/live-updates/version-targeting/#disable-auto-update-across-major-versions) * [Channels: Disable Auto Update strategies](/docs/live-updates/channels/#disable-auto-update-strategies) ### `disable_auto_update_to_minor` / `disable_auto_update_to_patch` [Section titled “disable\_auto\_update\_to\_minor / disable\_auto\_update\_to\_patch”](#disable_auto_update_to_minor--disable_auto_update_to_patch) **Cause** Channel policy is stricter (`minor` or `patch`) than the update being offered. **Fix** * Upload a bundle compatible with the current policy, or * change channel policy in dashboard/CLI. Related docs: * [Channels: Disable Auto Update strategies](/docs/live-updates/channels/#disable-auto-update-strategies) ### `disable_auto_update_to_metadata` [Section titled “disable\_auto\_update\_to\_metadata”](#disable_auto_update_to_metadata) **Cause** Channel uses metadata-based targeting (`version_number`) and the device baseline is below required `min_update_version`. **Fix** * Align device baseline (`CapacitorUpdater.version`) with installed native app version, or * adjust `min_update_version` / channel strategy. Related docs: * [Channels: Disable Auto Update strategies](/docs/live-updates/channels/#disable-auto-update-strategies) ### `disable_auto_update_under_native` [Section titled “disable\_auto\_update\_under\_native”](#disable_auto_update_under_native) **Cause** Channel prevents downgrades below the native baseline. **Fix** * Upload a bundle version greater than or equal to native baseline, or * disable “under native” downgrade protection for that channel. Related docs: * [Version Targeting: Auto-Downgrade Prevention](/docs/live-updates/version-targeting/#strategy-4-auto-downgrade-prevention) ### `cannot_update_via_private_channel` [Section titled “cannot\_update\_via\_private\_channel”](#cannot_update_via_private_channel) **Cause** Selected/default channel does not allow device self-assignment. **Fix** * Use a different channel with self-assignment enabled, or * make the channel public / enable self-assignment. Related docs: * [Channels: Using setChannel() from Your App](/docs/live-updates/channels/#using-setchannel-from-your-app) ### `unknown_version_build` / `semver_error` [Section titled “unknown\_version\_build / semver\_error”](#unknown_version_build--semver_error) **Cause** Device baseline version is missing (`unknown`) or not valid semver. **Fix** * Set `plugins.CapacitorUpdater.version` to a valid semver like `1.2.3`. * Sync and rebuild native app. Related docs: * [Channels: Bundle Versioning and Channels](/docs/live-updates/channels/#bundle-versioning-and-channels) * [Troubleshooting: Updates not applying](/docs/getting-started/troubleshooting/#updates-not-applying) ### `unsupported_plugin_version` [Section titled “unsupported\_plugin\_version”](#unsupported_plugin_version) **Cause** Updater plugin version is too old for current backend requirements. **Fix** * Upgrade `@capgo/capacitor-updater`. * Run `npx cap sync`. * Rebuild and reinstall native app. ### `disabled_platform_ios` / `disabled_platform_android` [Section titled “disabled\_platform\_ios / disabled\_platform\_android”](#disabled_platform_ios--disabled_platform_android) **Cause** Channel has updates disabled for that platform. **Fix** * Enable platform toggle on the channel. ### `disable_prod_build` / `disable_dev_build` / `disable_device` / `disable_emulator` [Section titled “disable\_prod\_build / disable\_dev\_build / disable\_device / disable\_emulator”](#disable_prod_build--disable_dev_build--disable_device--disable_emulator) **Cause** Channel disallows current build type or runtime target. **Fix** * Align channel options (`allow_prod`, `allow_dev`, `allow_device`, `allow_emulator`) with your test target. ### `key_id_mismatch` [Section titled “key\_id\_mismatch”](#key_id_mismatch) **Cause** Bundle encryption key and device key differ. **Fix** * Use the same encryption key/public key across app config and bundle encryption workflow. ### `no_channel` / `null_channel_data` [Section titled “no\_channel / null\_channel\_data”](#no_channel--null_channel_data) **Cause** No valid channel was resolved for the device. **Fix** * Set a cloud default channel, or * set `defaultChannel` in test builds, or * assign channel override for device. Related docs: * [Channels](/docs/live-updates/channels/) ### `on_premise_app` [Section titled “on\_premise\_app”](#on_premise_app) **Cause** The backend returned HTTP 429 with `on_premise_app`. This happens in three situations: 1. **App ID does not exist in Capgo** — the `app_id` sent by the device is not registered, so the backend has no record of it. 2. **App is flagged as on-premise** — the app exists but is configured for self-hosted updates, so the Capgo cloud endpoint refuses to serve it. 3. **Organization plan is cancelled** — the app’s organization no longer has an active subscription. **Common mistake** A typo in `plugins.CapacitorUpdater.appId` (in `capacitor.config.ts`) or a mismatch with the app ID registered in the Capgo dashboard. The backend cannot distinguish “unknown app” from “on-premise app”, so it returns the same error code. **Fix** * Verify the `app_id` matches exactly what is shown in the Capgo dashboard (case-sensitive). * If the app is not registered yet, run `npx @capgo/cli@latest app add`. * If the app is intentionally on-premise, set `plugins.CapacitorUpdater.updateUrl` to your self-hosted update endpoint instead of the Capgo cloud URL. * If the organization plan expired, renew or upgrade the plan. ## Quick diagnostic checklist [Section titled “Quick diagnostic checklist”](#quick-diagnostic-checklist) 1. Confirm app ID and channel are correct for the build. 2. Confirm `CapacitorUpdater.version` matches installed native app version. 3. Confirm channel policy (`disable_auto_update`) matches intended rollout. 4. Confirm platform/build target toggles allow this device. 5. Run `npx @capgo/cli@latest app debug` and read backend error code. ## Need more help? [Section titled “Need more help?”](#need-more-help) * [Troubleshooting](/docs/getting-started/troubleshooting/) * [How to get support](/docs/getting-help/) # Cordova > Exploring the potential availability of the capacitor-updater plugin for Cordova and the challenges involved in its development. You’ve been wondering if this plugin will ever be available for Cordova. We have started a R\&D repository for that, but it’s a huge amount of work. ## Problems [Section titled “Problems”](#problems) We know we can do it but for that, we have to read all the code of Cordova codebase as we did for Capacitor, to understand how to make it work with ap Capgo features. The Android version is easier to do since both use Java, but iOS needs a full rewrite because Swift is still not well-supported in Cordova ## Solution [Section titled “Solution”](#solution) In the mean time heres what you can do: * [Support us](https://github.com/sponsors/cap-go) on GitHub and we can prioritize that. This will need at least 1 month of work. * Hire us as a [Consultant](https://capgo.app/consulting/), we are used to help big companies migrate to Capacitor, it usually takes a month, and the [benefit](https://ionic.io/resources/articles/capacitor-vs-cordova-modern-hybrid-app-development) is huge for your team # Debugging > How to debug your updates of Capgo and understand the issue you can have with your configuration ## Understanding cloud logs: [Section titled “Understanding cloud logs:”](#understanding-cloud-logs) If you get a cloud refusal code and need concrete remediation steps, see [Common Update Problems](/docs/plugins/updater/commonproblems/). ### Sent from the backend [Section titled “Sent from the backend”](#sent-from-the-backend) | code | Description | | ------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **InvalidIp** | The user is located in a Google data center and the update is less than 4 hours old. This is done to prevent Google bots’ devices from counting as devices in your account. | | **needPlanUpgrade** (previously **needUpgrade**) | Indicates that you have reached the limit of your plan, and the device will not receive updates until you upgrade or until the next month. | | **noNew** | The device has the latest available version. | | **disablePlatformIos** | The device is on the iOS platform, but that is disabled in the channel settings. | | **disablePlatformAndroid** | The device is on the Android platform, but that is disabled in the channel settings. | | **disableAutoUpdate** | ”major" | | **disableAutoUpdateUnderNative** | The device has version (`1.2.3`), and the channel has an update (`1.2.2`) under the device version to send, but that is disabled in the channel settings. | | **disableDevBuild** | The device has a dev build, but that is disabled in the channel settings. | | **disableEmulator** | The device is an emulator, but that is disabled in the channel settings. | | **cannotGetBundle** | Failed to generate a valid signed URL for the bundle download. This occurs when the bundle URL generation fails or returns an invalid URL (not starting with http/https) and there’s no manifest available as a fallback. | | **cannotUpdateViaPrivateChannel** | The device tried to self-associate with a private channel, but the channel settings don’t allow device self-association (`allow_device_self_set` is false) and the channel is not public. | | **channelMisconfigured** | The channel is configured to disable auto-update by version number (`disable_auto_update: 'version_number'`), but the bundle’s `min_update_version` field is null, making it impossible to determine which devices should receive the update. | | **disableAutoUpdateMetadata** | Auto-update is disabled by version number metadata. The channel requires the device’s version to be at least `min_update_version`, but the device’s current version is lower than this threshold. | | **disableAutoUpdateToMajor** | Channel setting `disable_auto_update: 'major'` prevents updates that would increase the major version number (e.g., blocking 1.x.x from updating to 2.x.x). | | **disableAutoUpdateToMinor** | Channel setting `disable_auto_update: 'minor'` prevents updates that would increase the minor version number (e.g., blocking 1.2.x from updating to 1.3.x). | | **disableAutoUpdateToPatch** | Channel setting `disable_auto_update: 'patch'` prevents updates that would increase the patch version number, or allows only patch-level updates within the same major.minor version (e.g., 1.2.3 can update to 1.2.4 but not 1.2.2 or 1.3.0). | | **missingBundle** | The bundle assigned to this channel has no downloadable content. This means the bundle has no `external_url`, no `r2_path`, it’s not a built-in version, and there are no manifest entries available for download. | | **NoChannelOrOverride** | No default channel is configured for this app and the device has no specific channel override assigned. At least one must be present for updates to work. | | **rateLimited** | The device has been rate limited due to excessive requests. | | **keyMismatch** | The device’s encryption public key does not match the public key used to encrypt the bundle. This happens when: (1) The public key in your app’s `capacitor.config.json` is different from the one used when uploading the bundle, or (2) You rotated your encryption keys but haven’t updated all devices yet. The response includes both `deviceKeyId` and `bundleKeyId` (first 4 characters of each public key) to help identify the mismatch. To fix this, ensure the same key pair is used both for uploading bundles (CLI uses private key) and in the app (capacitor.config.json contains public key). | ### Sent from the device [Section titled “Sent from the device”](#sent-from-the-device) | code | Description | | -------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **ping** | Internal test action used to verify the stats system is working correctly. | | **get** | Info for downloading the new version has been sent to the device. | | **delete** | One bundle has been deleted on the device. | | **set** | A bundle has been set on the device. | | **set\_fail** | The bundle failed to set. | | **reset** | The device reset to the `builtin` bundle. | | **download\_XX** | A new bundle has been downloaded - progress indicated by XX% (increments of 10%). | | **download\_complete** | The new bundle has finished downloading. | | **download\_manifest\_start** | The device started downloading the update manifest. | | **download\_manifest\_complete** | The device finished downloading the update manifest. | | **download\_zip\_start** | The device started downloading the bundle archive. | | **download\_zip\_complete** | The device finished downloading the bundle archive. | | **download\_manifest\_file\_fail** | One manifest entry failed to download; the stats payload puts `version_name` in the form `version:fileName` to pinpoint the asset. | | **download\_manifest\_checksum\_fail** | The manifest file failed checksum validation. | | **download\_manifest\_brotli\_fail** | The manifest file failed to decompress using Brotli. | | **download\_fail** | The new bundle failed to download. | | **update\_fail** | The new bundle has been installed but failed to call `notifyAppReady`. | | **checksum\_fail** | The new bundle failed to validate the checksum. This can happen for several reasons: **1) Checksum type mismatch:** The latest version of the CLI and plugins (version 5.10.0+, 6.25.0+ or 7+) use SHA256 checksums, while older plugins used CRC32. If you see a checksum fail, check if the checksum is CRC32 (a shorter hash) rather than SHA256. This usually indicates the bundle was uploaded with an old version of the CLI. Verify your bundle version in the Capgo dashboard - bundles created since version 5.10.0/6.25.0/7 should use SHA256. If you’re seeing CRC32 checksums, ensure you have the latest plugin version installed locally (the CLI checks your local plugin version to determine which checksum type to upload), then upgrade your CLI and re-upload the bundle. **2) Encryption key mismatch (on plugin versions below 8.3.0 or 5/6/7.38.0):** On older plugin versions, if the device’s public key doesn’t match the key used to encrypt the bundle, the decryption will fail silently and cause a checksum failure. If you’re using encryption and see `checksum_fail`, verify that the public key in your app’s `capacitor.config.json` matches the private key used to upload the bundle. Upgrading to plugin version 8.3.0+ (or 5/6/7.38.0+) will give you a proper `keyMismatch` error from the server instead, making this issue easier to diagnose. | | **windows\_path\_fail** | The zip has files who contain windows path who are illegal | | **canonical\_path\_fail** | The path of files is not canonical | | **directory\_path\_fail** | There is an error in the path of zip files | | **unzip\_fail** | unzip failed | | **low\_mem\_fail** | Download failed because of low memory in the device | | **app\_moved\_to\_background** | The application entered the background state. | | **app\_moved\_to\_foreground** | The application entered the foreground state. | | **decrypt\_fail** | Failed to decrypt the downloaded bundle. | | **getChannel** | The current channel for the device was queried. | | **setChannel** | A channel was successfully set for the device. | | **uninstall** | The application was uninstalled or Capgo data cleared. | | **blocked\_by\_server\_url** | Server.url is present in your capacitor config, this make Capacitor serve remote url and ignore local files, while our updater is made to function with local file, Server.url Is consider by Capacitor Makers as bad practice in production and will lead to many issue and plugin not working correctly. | ### Bundle status [Section titled “Bundle status”](#bundle-status) * `SUCCESS`: install bundle done * `ERROR`: install or download failed * `PENDING`: Download done, pending release * `DELETED`: Bundle deleted, still presented for stats * `DOWNLOADING`: Currently downloading a bundle ## Understanding device logs: [Section titled “Understanding device logs:”](#understanding-device-logs) ### Debug command: [Section titled “Debug command:”](#debug-command) There is a debug command for Capgo cloud users. ```bash npx @capgo/cli@latest app debug ``` This will allow you to check all events happening in the app and find a solution if updates don’t happen. ### IOS [Section titled “IOS”](#ios) to find your logs on Xcode [Getting the Device Log in Xcode ](https://intercom.help/deploygate/en/articles/4682692-getting-the-device-log-in-xcode) ### Android: [Section titled “Android:”](#android) to find your logs on Android studio [View logs with Logcat ](https://developer.android.com/studio/debug/am-logcat) ### Explanations Logs [Section titled “Explanations Logs”](#explanations-logs) * `Failed to download from` **=>** same as **download\_fail** * `notifyAppReady was not called, roll back current bundle` => same as as **update\_fail** ## Finding the downloaded bundle in your device [Section titled “Finding the downloaded bundle in your device”](#finding-the-downloaded-bundle-in-your-device) ### iOS [Section titled “iOS”](#ios-1) To debug on iOS, you need to dump the app on your computer, you can do it like this: Xcode has a built-in feature for inspecting the file system of developer-installed apps on an iOS device. ![Xcode Window menu showing Devices and Simulators option](/ios_debug_update_1.webp) To achieve this: * Connect your device to your Mac and select Window > Devices in the Xcode menubar. * Select your device in the left pane under the Devices section. * This will show a list of developer-installed apps for that device. * Select the app you want to inspect and then select the 3 dots icon near the bottom of the screen. * Here you can view the current file system by selecting download a snapshot of it. ![Xcode Devices panel showing app container download option](/ios_debug_update_2.webp) Selecting Download Container… will download and export a snapshot of the file system as a .xcappdata file that you can browse through. ![Downloaded xcappdata file with Show Package Contents context menu](/ios_debug_update_3.webp) Right-click on this file and select Show Package Contents to open the folder. Open the App Data folder, and you should now see a few folders like Documents, Library, tmp, etc. ![iOS app container folder structure showing Documents and Library folders](/ios_debug_update_4.webp) Then you will find a version in 2 folders: `library/NoCloud/ionic_built_snapshots` is necessary after the app reboot and `documents/versions` for hot reload ### Android [Section titled “Android”](#android-1) To debug on Android, you need to access the device from Android Studio: * Click View > Tool Windows > Device File Explorer or click the Device File Explorer button in the tool window bar to open the Device File Explorer. * Select a device from the dropdown list. * Open the path **data/data/APP\_NAME/** where **APP\_NAME is your app ID.** ![Android Studio Device File Explorer showing app data directory](/android_debug_update.webp) Then Find the `versions` folder to see all the versions Did you know? On Android, all versions are stored in one folder, unlike IOS where it has to be duplicated in two locations. ## Understanding ios production crash logs [Section titled “Understanding ios production crash logs”](#understanding-ios-production-crash-logs) [How to review your app's crash logs ](https://developer.apple.com/news/?id=nra79npr) # Events > All events you can listen to in the Capacitor Updater plugin for monitoring update status and progress The Capacitor Updater plugin provides several events you can listen to for monitoring the update process and responding to different states. ## Event Listener Setup [Section titled “Event Listener Setup”](#event-listener-setup) To listen to events, use the `addListener` method on the `CapacitorUpdater` object: ```typescript import { CapacitorUpdater } from '@capgo/capacitor-updater'; // Add a listener const listener = await CapacitorUpdater.addListener('eventName', (event) => { // Handle the event }); // Remove the listener when no longer needed listener.remove(); // Remove all listeners await CapacitorUpdater.removeAllListeners(); ``` ## Available Events [Section titled “Available Events”](#available-events) ### `download` [Section titled “download”](#download) Fired during the bundle download process. Provides download progress information. ```typescript CapacitorUpdater.addListener('download', (event) => { console.log(`Download progress: ${event.percent}%`); console.log('Bundle info:', event.bundle); }); ``` **Event Data:** * `percent`: number - Download progress percentage (0-100) * `bundle`: BundleInfo - Information about the bundle being downloaded Note This event fires multiple times during download to report progress. ### `noNeedUpdate` [Section titled “noNeedUpdate”](#noneedupdate) Fired when a check for updates determines that no update is needed. ```typescript CapacitorUpdater.addListener('noNeedUpdate', (event) => { console.log('App is up to date'); console.log('Current bundle:', event.bundle); }); ``` **Event Data:** * `bundle`: BundleInfo - Information about the current bundle ### `updateAvailable` [Section titled “updateAvailable”](#updateavailable) Fired when a new update is available for download. ```typescript CapacitorUpdater.addListener('updateAvailable', (event) => { console.log('Update available'); console.log('New bundle:', event.bundle); // You can trigger a download here if needed }); ``` **Event Data:** * `bundle`: BundleInfo - Information about the available update bundle ### `downloadComplete` [Section titled “downloadComplete”](#downloadcomplete) Fired when a bundle download has completed successfully. ```typescript CapacitorUpdater.addListener('downloadComplete', (event) => { console.log('Download completed'); console.log('Downloaded bundle:', event.bundle); // You might want to set this bundle as next }); ``` **Event Data:** * `bundle`: BundleInfo - Information about the downloaded bundle ### `majorAvailable` [Section titled “majorAvailable”](#majoravailable) Fired when a major update is available but blocked by auto-update settings. ```typescript CapacitorUpdater.addListener('majorAvailable', (event) => { console.log('Major update available:', event.version); // Notify user about major update }); ``` **Event Data:** * `version`: string - The version number of the major update Tip Major updates typically require user confirmation or app store updates. Use this event to notify users appropriately. ### `updateFailed` [Section titled “updateFailed”](#updatefailed) Fired when an update has failed to install at the next app start. ```typescript CapacitorUpdater.addListener('updateFailed', (event) => { console.error('Update failed to install'); console.log('Failed bundle:', event.bundle); // Handle rollback or retry logic }); ``` **Event Data:** * `bundle`: BundleInfo - Information about the bundle that failed to install ### `downloadFailed` [Section titled “downloadFailed”](#downloadfailed) Fired when a bundle download has failed. ```typescript CapacitorUpdater.addListener('downloadFailed', (event) => { console.error('Download failed for version:', event.version); // Handle download retry logic }); ``` **Event Data:** * `version`: string - The version that failed to download ### `appReloaded` [Section titled “appReloaded”](#appreloaded) Fired when the app has been reloaded. ```typescript CapacitorUpdater.addListener('appReloaded', () => { console.log('App has been reloaded'); // Perform any necessary reinitialization }); ``` **Event Data:** None ### `appReady` [Section titled “appReady”](#appready) Fired when the app is ready to use after an update. ```typescript CapacitorUpdater.addListener('appReady', (event) => { console.log('App is ready'); console.log('Current bundle:', event.bundle); console.log('Status:', event.status); }); ``` **Event Data:** * `bundle`: BundleInfo - Information about the current bundle * `status`: string - The ready status Caution Remember to call `notifyAppReady()` within the configured timeout (default 10 seconds) to prevent automatic rollback. ## BundleInfo Object [Section titled “BundleInfo Object”](#bundleinfo-object) Many events include a `BundleInfo` object with the following properties: ```typescript interface BundleInfo { id: string; // Unique bundle identifier version: string; // Bundle version downloaded: string; // Download timestamp checksum?: string; // Bundle checksum (if available) status: BundleStatus; // Bundle status } ``` Where `BundleStatus` can be: * `'success'` - Bundle downloaded successfully * `'error'` - Bundle download/installation failed * `'pending'` - Bundle is pending to be set as next * `'downloading'` - Bundle is currently downloading ## Example: Complete Update Flow [Section titled “Example: Complete Update Flow”](#example-complete-update-flow) Here’s an example of handling the complete update flow with events: Caution This `UpdateManager` class does not include the `CapacitorUpdater.notifyAppReady()` call required for auto-update flow. Please see the [placing notifyAppReady call correctly](/docs/plugins/updater/notify-app-ready/#placing-notifyappready-call-correctly) docs for more information. ```typescript import { CapacitorUpdater } from '@capgo/capacitor-updater'; export class UpdateManager { private listeners: any[] = []; async setupListeners() { // Listen for available updates this.listeners.push( await CapacitorUpdater.addListener('updateAvailable', async (event) => { console.log('Update available:', event.bundle.version); // Auto-download the update await CapacitorUpdater.download({ url: event.bundle.url, version: event.bundle.version }); }) ); // Monitor download progress this.listeners.push( await CapacitorUpdater.addListener('download', (event) => { console.log(`Downloading: ${event.percent}%`); // Update UI progress bar this.updateProgressBar(event.percent); }) ); // Handle download completion this.listeners.push( await CapacitorUpdater.addListener('downloadComplete', async (event) => { console.log('Download complete:', event.bundle.version); // Set as next bundle await CapacitorUpdater.next({ id: event.bundle.id }); }) ); // Handle failures this.listeners.push( await CapacitorUpdater.addListener('downloadFailed', (event) => { console.error('Download failed:', event.version); this.showError('Update download failed. Please try again later.'); }) ); this.listeners.push( await CapacitorUpdater.addListener('updateFailed', (event) => { console.error('Update installation failed:', event.bundle.version); this.showError('Update installation failed. The app has been rolled back.'); }) ); // Handle app ready this.listeners.push( await CapacitorUpdater.addListener('appReady', async (event) => { console.log('App ready with bundle:', event.bundle.version); }) ); } cleanup() { // Remove all listeners when no longer needed this.listeners.forEach(listener => listener.remove()); this.listeners = []; } private updateProgressBar(percent: number) { // Update your UI progress bar } private showError(message: string) { // Show error to user } } ``` ## Best Practices [Section titled “Best Practices”](#best-practices) 1. **Always call `notifyAppReady()`**: When using auto-update, always call this method after your app initializes to prevent rollback. 2. **Handle failures gracefully**: Implement proper error handling for download and update failures. 3. **Provide user feedback**: Use the download progress event to show update progress to users. 4. **Clean up listeners**: Remove event listeners when they’re no longer needed to prevent memory leaks. 5. **Test update scenarios**: Test various update scenarios including failures, rollbacks, and major updates. # Getting Started > Quick start guide for integrating live updates into your Capacitor app with the Updater plugin. ## Installation [Section titled “Installation”](#installation) * npm ```bash bun add @capgo/capacitor-updater bunx cap sync ``` * yarn ```bash yarn add @capgo/capacitor-updater bunx cap sync ``` * pnpm ```bash pnpm add @capgo/capacitor-updater bunx cap sync ``` * bun ```bash bun add @capgo/capacitor-updater bunx cap sync ``` ## Quick Start [Section titled “Quick Start”](#quick-start) For most users, we recommend following the [main Quickstart guide](/docs/getting-started/quickstart/) which covers both the plugin installation and Capgo cloud integration. This getting-started guide focuses on the technical plugin details for advanced users who want to understand the underlying mechanisms or implement self-hosted updates. ## Overview [Section titled “Overview”](#overview) The Capacitor Updater plugin enables over-the-air (OTA) updates for your Capacitor applications. This allows you to push updates to your app without going through app store reviews. ## How It Works [Section titled “How It Works”](#how-it-works) 1. **Bundle Download**: The plugin downloads update bundles (ZIP files containing your web assets) 2. **Extraction**: Bundles are extracted to the device’s storage 3. **Hot Reload**: The app switches to the new bundle without requiring a restart 4. **Fallback**: If an update fails, the app reverts to the previous working version ## Usage Modes [Section titled “Usage Modes”](#usage-modes) ### 1. Auto-Update Mode (Recommended) [Section titled “1. Auto-Update Mode (Recommended)”](#1-auto-update-mode-recommended) The simplest way to use the plugin with automatic update management: ```typescript import { CapacitorUpdater } from '@capgo/capacitor-updater'; // Plugin handles everything automatically // Configure in capacitor.config.ts ``` Add to your `capacitor.config.ts`: ```typescript { plugins: { CapacitorUpdater: { autoUpdate: true, updateUrl: 'https://your-update-server.com/api/updates' } } } ``` ### 2. Manual Mode [Section titled “2. Manual Mode”](#2-manual-mode) For advanced control over the update process: ```typescript import { CapacitorUpdater } from '@capgo/capacitor-updater'; // Download an update const bundle = await CapacitorUpdater.download({ url: 'https://your-server.com/updates/v1.0.1.zip', version: '1.0.1' }); // Set the bundle (will be used on next app start) await CapacitorUpdater.set({ id: bundle.id }); // Or reload immediately await CapacitorUpdater.reload(); ``` ## Platform Configuration [Section titled “Platform Configuration”](#platform-configuration) ### iOS [Section titled “iOS”](#ios) No additional configuration required. The plugin works out of the box. ### Android [Section titled “Android”](#android) No additional configuration required. The plugin works out of the box. ## Basic API Usage [Section titled “Basic API Usage”](#basic-api-usage) ### Download an Update [Section titled “Download an Update”](#download-an-update) ```typescript import { CapacitorUpdater } from '@capgo/capacitor-updater'; const bundle = await CapacitorUpdater.download({ url: 'https://example.com/update.zip', version: '1.0.1' }); console.log('Downloaded bundle:', bundle.id); ``` ### Set Active Bundle [Section titled “Set Active Bundle”](#set-active-bundle) ```typescript // Set bundle to be used on next app start await CapacitorUpdater.set({ id: bundle.id }); ``` ### Reload with New Bundle [Section titled “Reload with New Bundle”](#reload-with-new-bundle) ```typescript // Reload app immediately with new bundle await CapacitorUpdater.reload(); ``` ### List Bundles [Section titled “List Bundles”](#list-bundles) ```typescript const { bundles } = await CapacitorUpdater.list(); console.log('Available bundles:', bundles); ``` ### Delete a Bundle [Section titled “Delete a Bundle”](#delete-a-bundle) ```typescript await CapacitorUpdater.delete({ id: 'bundle-id' }); ``` ### Get Current Bundle [Section titled “Get Current Bundle”](#get-current-bundle) ```typescript const { bundle } = await CapacitorUpdater.current(); console.log('Current bundle:', bundle.version); ``` ## Event Listeners [Section titled “Event Listeners”](#event-listeners) Listen for update events: ```typescript import { CapacitorUpdater } from '@capgo/capacitor-updater'; // Listen for download progress CapacitorUpdater.addListener('download', (info) => { console.log('Download progress:', info.percent); }); // Listen for download completion CapacitorUpdater.addListener('downloadComplete', (bundle) => { console.log('Download complete:', bundle.version); }); // Listen for update failures CapacitorUpdater.addListener('updateFailed', (error) => { console.error('Update failed:', error); }); // Listen for successful updates CapacitorUpdater.addListener('updateAvailable', (info) => { console.log('Update available:', info.version); }); ``` ## Configuration Options [Section titled “Configuration Options”](#configuration-options) Configure the plugin in your `capacitor.config.ts`: ```typescript { plugins: { CapacitorUpdater: { // Auto-update settings autoUpdate: true, updateUrl: 'https://api.example.com/updates', // Update behavior resetWhenUpdate: true, directUpdate: false, // Version settings version: '1.0.0', // Security allowModifyUrl: false, // Stats collection statsUrl: 'https://api.example.com/stats', // Channel (for Capgo cloud) defaultChannel: 'production' } } } ``` ## Integration Patterns [Section titled “Integration Patterns”](#integration-patterns) ### With Capgo Cloud [Section titled “With Capgo Cloud”](#with-capgo-cloud) The easiest way to get started: ```typescript // Install the Capgo CLI bun add -g @capgo/cli // Login to Capgo npx @capgo/cli login // Upload your first bundle npx @capgo/cli bundle upload // The plugin auto-updates from Capgo cloud ``` See the [main Quickstart guide](/docs/getting-started/quickstart/) for details. ### Self-Hosted Updates [Section titled “Self-Hosted Updates”](#self-hosted-updates) Host your own update server: ```typescript // Configure your update endpoint { plugins: { CapacitorUpdater: { autoUpdate: true, updateUrl: 'https://your-server.com/api/check-update' } } } ``` Your server should return: ```json { "version": "1.0.1", "url": "https://your-server.com/updates/1.0.1.zip" } ``` See [Self-Hosted Mode](/docs/plugins/updater/self-hosted/getting-started/) for complete details. ### Manual Update Flow [Section titled “Manual Update Flow”](#manual-update-flow) Complete control over updates: ```typescript import { CapacitorUpdater } from '@capgo/capacitor-updater'; async function checkAndUpdate() { // Check for updates from your server const response = await fetch('https://api.example.com/check-update'); const { version, url } = await response.json(); // Download the update const bundle = await CapacitorUpdater.download({ url, version }); // Notify bundle is ready await CapacitorUpdater.notifyAppReady(); // Set as next version await CapacitorUpdater.set({ id: bundle.id }); // Reload when ready await CapacitorUpdater.reload(); } ``` ## Best Practices [Section titled “Best Practices”](#best-practices) * Always call `notifyAppReady()` when your app successfully loads * Test updates thoroughly before pushing to production * Implement proper error handling for network failures * Use version numbers consistently * Keep bundle sizes small for faster downloads * Monitor update success rates ## Next Steps [Section titled “Next Steps”](#next-steps) * [Plugin API Reference](/docs/plugins/updater/api/) - Complete API documentation * [Plugin Settings](/docs/plugins/updater/settings/) - All configuration options * [Events](/docs/plugins/updater/events/) - Available update events * [Self-Hosted Mode](/docs/plugins/updater/self-hosted/getting-started/) - Run your own update server * [Local Development](/docs/plugins/updater/local-dev/getting-started/) - Test updates locally * [Debugging](/docs/plugins/updater/debugging/) - Troubleshooting guide ## Support [Section titled “Support”](#support) * [Known Issues](/docs/plugins/updater/known-issues/) - Common problems and solutions * [GitHub Discussions](https://github.com/Cap-go/capacitor-updater/discussions) - Community support * [Discord](https://discord.gg/VnYRvBfgA6) - Real-time chat # Known issues > Known issues with Capacitor and Capgo, and our updater, this page will help you understand the weird issue you have with our tool ## Ionic live reload [Section titled “Ionic live reload”](#ionic-live-reload) * When you develop, if you use the Ionic live reload feature from the CLI, it will override the plugin, so you will never see your update. ## Quasar live reload [Section titled “Quasar live reload”](#quasar-live-reload) * It uses the same system as ionic under the hood, so you will not see your updates. ## Updates fail [Section titled “Updates fail”](#updates-fail) * This usually happens when large updates (> 20mb) are pushed, a big percentage of users will not get the last version.\ In the past, users needed to keep the app open until the download was done, now we use background download, but it’s still limited to a few seconds. ## Android [Section titled “Android”](#android) ### Cannot download [Section titled “Cannot download”](#cannot-download) We have seen some issues with devices in india, and got user on the call, made them try different DNS servers, and it worked. So if you have the issue, try to use a different DNS server like Cloudflare or Google DNS. Cloudflare: 1.1.1.1 and 1.0.0.1 Google DNS: 8.8.8.8 and 8.8.4.4 or dns.google [How to setup a preferred DNS server on Android? ](https://www.androidpolice.com/use-preferred-dns-server-android-tutorial/) ### Self Hosted [Section titled “Self Hosted”](#self-hosted) When you are pushing a self-hosted update, be mindful you cannot use “HTTP” endpoint as it’s against the security policies of Android apps, if you still want to do it, follow this guide: [How to allow all Network connection types HTTP and HTTPS in Android (9) Pie? ](https://stackoverflow.com/a/51902630/5511370) ### Unzip [Section titled “Unzip”](#unzip) Unzip issue: DEFLATED entries can have EXT descriptor If you zipped your bundle with something different than the CLI, the format or your zip could be incorrect, please use the CLI command `npx @capgo/cli zip BUNDLE_FOLDER`. This is a known issue of Java: [Unzip issue: DEFLATED entries can have EXT descriptor ](https://bugs.openjdk.org/browse/JDK-8143613) ### Clearfix issue [Section titled “Clearfix issue”](#clearfix-issue) * If you have issues with usesCleartextTraffic, it’s because the plugin follows the good practice recommended by sonar cloud, in 90% of the cases it will work just fine, but with some plugins that causes issues. To fix it, add in `android/app/src/main/AndroidManifest.xml` in the `<application>` key : ```xml tools:replace="android:usesCleartextTraffic" xmlns:tools="http://schemas.android.com/tools" ``` ## IOS [Section titled “IOS”](#ios) ### Privacy manifest [Section titled “Privacy manifest”](#privacy-manifest) Add the `NSPrivacyAccessedAPICategoryUserDefaults` dictionary key to your [Privacy Manifest](https://capacitorjs.com/docs/ios/privacy-manifest) (usually `ios/App/PrivacyInfo.xcprivacy`): ```xml <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>NSPrivacyAccessedAPITypes</key> <array> <!-- Add this dict entry to the array if the file already exists. --> <dict> <key>NSPrivacyAccessedAPIType</key> <string>NSPrivacyAccessedAPICategoryUserDefaults</string> <key>NSPrivacyAccessedAPITypeReasons</key> <array> <string>CA92.1</string> </array> </dict> </array> </dict> </plist> ``` We recommend to declare [`CA92.1`](https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api#4278401) as the reason for accessing the [`UserDefaults`](https://developer.apple.com/documentation/foundation/userdefaults) API. ### Network permissions [Section titled “Network permissions”](#network-permissions) When using local server for testing update, the app will ask for network permission, it’s a normal behavior, it’s not the case when you use a remote server. ## Both OS [Section titled “Both OS”](#both-os) When doing manual mode updates, some events are not easy to catch, for example the update fail triggers just before your JS code reloads, so you will not be able to catch it. One alternative is to list the bundles and check error stats to know if the update fails. We need to find a better way to handle this in the future, but it’s not a priority, since auto mode is the recommended way to do update. PRs are welcome to help us improve this. ## CLI [Section titled “CLI”](#cli) if your CLI has troubles doing anything, Check if **appId** and **appName** are present in your **capacitor.config.ts** Follow the guide of the official doc: [Capacitor Configuration ](https://capacitorjs.com/docs/config) # Using the capacitor updater with self-hosted capgo > How to use the capacitor updater with self-hosted Capgo, be fully autonomous with your own instance of Capgo ## What this tutorial will cover? [Section titled “What this tutorial will cover?”](#what-this-tutorial-will-cover) This tutorial will show how to use capacitor updater in a dev environment with self hosted capgo ## Requirements [Section titled “Requirements”](#requirements) 1. [Cloned capgo](https://github.com/Cap-go/capgo) ## Getting started [Section titled “Getting started”](#getting-started) To use the capacitor updater with self-hosted capgo edit the `capacitor.config.ts` from your app directory and set it like this: ```ts const config: CapacitorConfig = { appId: 'com.demo.app', appName: 'demoApp', webDir: 'dist', bundledWebRuntime: false, plugins: { CapacitorUpdater : { statsUrl: "https://localhost:54321/functions/v1/stats", channelUrl: "https://localhost:54321/functions/v1/channel_self", updateUrl: "https://localhost:54321/functions/v1/updates" }, }, }; ``` This will enable you to use local capgo in development. However, by default, this is not enough. > By default iOS, Android, and Electron expect you to use HTTPS, you need to use a tool like Ngrock or localcan to proxy your API in https. There is a way in Android to enable [plaintext communication](https://developer.android.com/topic/security/risks/cleartext). This can be achieved by modifying [AndroidManifest.xml](https://github.com/Cap-go/capacitor-updater/blob/main/android/src/main/AndroidManifest.xml) and adding `android:usesCleartextTraffic="true"` in the `application` tag A full example of this change can be seen [here](https://gist.github.com/WcaleNieWolny/061a015acdebe35eaf3afd7030797701) There also could be a problem that prevents the android app from connecting. If you do not see any requests being send to edge functions run ```bash adb reverse tcp:54321 tcp:54321 ``` # Using the CLI with self-hosted capgo > This guide explains how to use the CLI with a self-hosted Capgo instance, enabling you to utilize Capgo tools on your own server instead of the cloud service. ## What this tutorial will cover? [Section titled “What this tutorial will cover?”](#what-this-tutorial-will-cover) This tutorial will show how to use CLI in a dev environment with self hosted capgo ## Getting started [Section titled “Getting started”](#getting-started) To use the CLI with self-hosted capgo edit the `capacitor.config.ts` from your app directory and set it like this: ```ts const config: CapacitorConfig = { appId: 'com.demo.app', appName: 'demoApp', webDir: 'dist', bundledWebRuntime: false, plugins: { CapacitorUpdater : { localHost: "http://localhost:5173", localWebHost: "http://localhost:5173", localSupa: "http://localhost:54321", localSupaAnon: "see_notes", }, }, }; ``` Note: To get `localSupaAnon` please follow [this tutorial](/docs/plugins/updater/local-dev/getting-started/) and copy the `anon key` into `localSupaAnon` # Contributing > A detailed guide on how to contribute to Capgo's open source projects, including the benefits of contributing, the steps involved in making contributions, and the resources available to assist contributors in the process ## Why contribute? [Section titled “Why contribute?”](#why-contribute) First of all, thank you for considering contributing to capgo open source projects! It’s people like you that make capgo open source projects such great tools. Here are some reasons you might want to cinsder to contribute: * Contributing to capgo open source projects is a great way to earn some money from the [countless bounties](https://console.algora.io/org/Capgo) that are offered by the capgo team * Contributing to capgo open source projects is a great way to add a feature you would like to see * Contributing to capgo open source projects is a great way to fix a bug you encountered * [Capgo main’s license](https://github.com/Cap-go/capgo/blob/main/LICENSE) requires you to open source any changes you make to it. By contributing your code, you get to keep your changes open source and let others use it ## How to contribute [Section titled “How to contribute”](#how-to-contribute) * First of all, you need to fork the repository you want to contribute to * Second of all you need to commit and push your changes to that repository * Lastly, you need to open a pull request * That’s it! Now you just need to wait for the capgo team to review your PR ## Further documents to read [Section titled “Further documents to read”](#further-documents-to-read) * Capgo’s [CONTRIBUTING.MD](https://github.com/Cap-go/capgo/blob/main/CONTRIBUTING.md) * Capgo’s [BOUNTY.md](https://github.com/Cap-go/capgo/blob/main/BOUNTY.md) # Getting started > This tutorial will show how to start the Supabase from scratch as well as start edge functions, to run Capgo on your own ## What this tutorial will cover? [Section titled “What this tutorial will cover?”](#what-this-tutorial-will-cover) This tutorial will show how to start the supabase from scratch as well as start edge functions ## Requirements [Section titled “Requirements”](#requirements) 1. Cloned [capgo](https://github.com/Cap-go/capgo) 2. [supabase](https://supabase.com/) ## Getting started [Section titled “Getting started”](#getting-started) To get started run ```bash supabase start ``` Next should see something like this: ```js Started supabase local development setup. API URL: http://localhost:54321 GraphQL URL: http://localhost:54321/graphql/v1 DB URL: postgresql://postgres:postgres@localhost:54322/postgres Studio URL: http://localhost:54323 Inbucket URL: http://localhost:54324 JWT secret: [truncated] anon key: supa_key_anon service_role key: supa_key_admin ``` Next open `configs.json` and set the following values: ```json { "base_domain": { "prod": "console.capgo.app", "development": "development.console.capgo.app", "local": "localhost:3332" }, "supa_anon": { "prod": "supa_key_anon", "development": "supa_key_anon", "local": "supa_key_anon" }, "supa_url": { "prod": "http://localhost:54321", "development": "http://localhost:54321", "local": "http://localhost:54321" } } ``` where `supa_key_anon` is the value from the previous step. Danger ⚠️ Do not commit `configs.json` into the remote repo Next, verify that you can go to [localhost:54323](http://localhost:54323/projects) and that the table `users` looks something like this ![Supabase dashboard showing users table](/supabase.webp) If it does start edge functions by running: ```bash supabase functions serve ``` and start frontend by running: ```bash bun run serve ``` # Placing CapacitorUpdater.notifyAppReady() call correctly > How to properly place the CapacitorUpdater.notifyAppReady() call in your app to ensure correct auto-update flow. The placement of the `CapacitorUpdater.notifyAppReady()` call is crucial for the correct auto-update flow. If not done correctly, the app will not be able to update to the latest version. Each version that does not call `notifyAppReady()` within 10 seconds will be marked as invalid and will be replaced by the previous valid version or the default (built-in) version. In this guide we will show you how to properly place the `notifyAppReady()` call in your app to ensure correct auto-update flow. ### `notifyAppReady()` Call Placement questionnaire [Section titled “notifyAppReady() Call Placement questionnaire”](#notifyappready-call-placement-questionnaire) <!-- Custom Steps Component --> 1. **What language/framework do you primarily use in your app?** ![JS + DOM API](/icons/js.svg) JS + DOM API ![TS + DOM API](/icons/ts.svg) TS + DOM API ![React](/icons/react.svg) React ![Angular](/icons/angular.svg) Angular ![Vue](/icons/vue.svg) Vue ![Svelte](/icons/svelte.svg) Svelte ![Qwik](/icons/qwik.svg) Qwik <!-- Styles live in src/css/docs.css (Astro drops component <style> blocks from MDX pages during build) --> 2. **** 3. **** 4. **** <!-- Styles live in src/css/docs.css (Astro drops component <style> blocks from MDX pages during build) --> Note If you cannot find your framework in the questionnaire, please don’t hesitate to ask on our [Discord](https://discord.capgo.app). # Auto Update > How to use the update endpoint of Capgo with the auto-update plugin in self-hosted mode, what they are used for and what to expect This documentation will explain how to run your auto-update server. ## Serve your bundle [Section titled “Serve your bundle”](#serve-your-bundle) Make sure your bundle is served over HTTPS, and the server has the right CORS headers to allow the app to download the update. e.g. `https://myserver.com/app/updates/updates.json` If you’re unfamiliar with serving a bundle, we recommend you try Capgo Cloud or see an example here: [Serving a Bundle ](/docs/plugins/updater/self-hosted/handling-updates/) ## Configuration [Section titled “Configuration”](#configuration) Add an `updateUrl` to your `capacitor.config.json`. ```json { "plugins": { "CapacitorUpdater": { "updateUrl": "https://myserver.com/app/updates/updates.json", } } } ``` Caution When you are pushing a self-hosted update, be mindful you cannot use “HTTP” endpoint as it’s against the security policies of Android apps, for testing purposes you can [allow it](https://stackoverflow.com/questions/45940861/android-8-cleartext-http-traffic-not-permitted). ## Update API [Section titled “Update API”](#update-api) The plugin will do a POST call to your API each time the app is open, with this body: ```typescript interface AppInfos { "platform": "ios" | "android" | "electron", "device_id": "UUID_of_device_unique_by_install", "app_id": "APPID_FROM_CAPACITOR_CONFIG", "custom_id": "your_custom_id_set_on_runtime", "plugin_version": "PLUGIN_VERSION", "version_build": "VERSION_NUMBER_FROM_NATIVE_CODE", "version_code": "VERSION_CODE_FROM_NATIVE_CODE", "version_name": "LAST_DOWNLOADER_VERSION" | "builtin" "version_os": "VERSION_OF_SYSTEM_OS", "is_emulator": boolean, "is_prod": boolean, } ``` The server API should respond, in JSON, to the capacitor-updater plugin. With this data if an update is necessary: ```json { "version": "1.2.3", "url": "https://myserver.com/app/updates/my-new-app-2.0.0.zip", "checksum": "sha256_checksum_of_bundle" } ``` In Auto-update mode the server should compare the versions and return the right one, if the URL key is present, the plugin starts the download process. If you add “message” and “error” key, the version will not be set, and the message will be displayed in logs instead. `version` key should be in [`semver`](https://semver.org/) format. The zip should have `index.html` as a file at the root, or only one folder at the root with `index.html` inside. You can use the command of the CLI to zip your bundle: Create a bundle with your files to serve from your server ```bash npx @capgo/cli bundle zip --path [/path/to/my/bundle] ``` ## Generating Bundle Checksum [Section titled “Generating Bundle Checksum”](#generating-bundle-checksum) **Important:** You must use the Capgo CLI to create your bundle zip file. The Capgo plugin requires a specific zip format and structure that is only guaranteed when using the official CLI tool. Standard zip utilities may create incompatible archives. To generate the checksum for your bundle, use the Capgo CLI zip command with the `--json` flag: Create bundle with checksum information ```bash npx @capgo/cli bundle zip [appId] --json ``` This command will: * Create a properly formatted zip file compatible with the Capgo plugin * Generate the SHA256 checksum for integrity verification * Output bundle information in JSON format Example output: ```json { "version": "1.2.3", "checksum": "a1b2c3d4e5f6789...", "size": 1234567 } ``` Use the `checksum` value from this output in your API response to ensure the plugin can verify the bundle integrity before installation. # Encrypted Bundles > A comprehensive guide on utilizing the manual update plugin in a self-hosted environment, detailing the steps and processes involved in managing encrypted bundles for secure and efficient updates. ## End-to-end Encryption [Section titled “End-to-end Encryption”](#end-to-end-encryption) Starting with version 4.15.0 the plugin allows you to send encrypted updates. ### Step 1: Create a private key [Section titled “Step 1: Create a private key”](#step-1-create-a-private-key) Create a private key ```bash npx @capgo/cli key create ``` ### Step 2: Create and zip your bundle [Section titled “Step 2: Create and zip your bundle”](#step-2-create-and-zip-your-bundle) Create bundle zip with checksum ```bash npx @capgo/cli bundle zip [appId] --key-v2 --json ``` The `--key-v2` flag uses the new encryption system with better checksums, and the `--json` flag will output the bundle information including the checksum that you’ll need for encryption. ### Step 3: Encrypt your bundle [Section titled “Step 3: Encrypt your bundle”](#step-3-encrypt-your-bundle) Encrypt bundled zip with checksum ```bash npx @capgo/cli encrypt [path/to/zip] [checksum] ``` The `checksum` parameter is the SHA256 checksum generated by the zip command in step 2. The encrypt command will return an `ivSessionKey` and generate an encrypted checksum.Remember to rename `ivSessionKey` key as `session_key` in the update payload. ### Step 4: Use in your update payload [Section titled “Step 4: Use in your update payload”](#step-4-use-in-your-update-payload) ```json { "version": "1.2.3", "url": "https://myserver.com/app/updates/my-new-app-2.0.0.zip", "session_key": "encrypted_session_key", "checksum": "encrypted_checksum_from_encrypt_command" } ``` The `session_key` is the `ivSessionKey` returned by the encrypt command, and the `checksum` is the encrypted checksum generated during encryption (not the original checksum from the zip command). Then your app will be able to use the private key to decrypt the `session_key` and use the decrypted `session_key` to decrypt the update. The encrypted checksum ensures bundle integrity verification. ## Learn More [Section titled “Learn More”](#learn-more) [End-to-End Encryption Guide ](https://capgo.app/blog/introducing-end-to-end-security-to-capacitor-updater-with-code-signing/)Deep dive into how Capgo's encryption system works with RSA + AES cryptography [Self-hosted Live Updates ](https://capgo.app/blog/self-hosted-live-updates/)Complete workflow for setting up self-hosted updates # Getting started > A comprehensive guide on setting up and managing your own auto-update server for seamless application updates and maintenance This documentation will explain how to run your own auto-update server. ## Introduction [Section titled “Introduction”](#introduction) If you find this work helpful, please consider supporting my work by becoming a [Github sponsor](https://github.com/sponsors/riderx). I made a bet to open-source all the code I built here instead of paywalling it. By opening it up instead of fighting and hiding, I believe we can make the world a better place. Furthermore, I want to focus on Capgo tooling, and make it an open and transparent business. But to make it possible, it is necessary for all of us to do our part, including you 🥹. If Capgo doesn’t suit you, then pay your own price and [back a bootstrapped Maker](https://github.com/sponsors/riderx) on your terms. [Consider Contributing ](/docs/plugins/updater/local-dev/contributing/) ## Features parity [Section titled “Features parity”](#features-parity) If you choose to go with your own server, you will lose the 5-min setup flow.\ You need to implement all of these features yourself. | Features | Capgo | Self hosted | | ------------------------ | ----- | ----------- | | Updates | ✅ | 🚧 | | Auto revert | ✅ | 🚧 | | Email alerts on fail | ✅ | 🚧 | | Channels | ✅ | 🚧 | | Channels Override | ✅ | 🚧 | | Device Override | ✅ | 🚧 | | Channels Settings | ✅ | 🚧 | | Device Settings | ✅ | 🚧 | | Custom ID | ✅ | 🚧 | | Auto Set Channels | ✅ | 🚧 | | API Channels | ✅ | 🚧 | | Updates Statistics | ✅ | 🚧 | | Fail Download Statistics | ✅ | 🚧 | | App Usage Statistics | ✅ | 🚧 | | Update Encryption | ✅ | 🚧 | | Delta (manifest) updates | ✅ | ❌ | Danger If you send a bad update to your users you can and will break their app. > Be mindful that you can’t use the Capgo cloud and your server at the same time. Danger The Over-the-Air (OTA) update feature is applicable only for modifications made to HTML, CSS, and JavaScript files. If you make any changes to the native code, such as updates to Capacitor plugins, it is mandatory to resubmit the application to the app store for approval. ## Choose between Auto and Manual [Section titled “Choose between Auto and Manual”](#choose-between-auto-and-manual) In auto mode, part of the logic is handled by the Native code, updates are decided server side, this is more secure and allows fine grain updates, partial deployment to one device or group and more. In manual mode, all the logic is handled by the JS. [Auto Update ](/docs/plugins/updater/self-hosted/auto-update/) [Manual ](/docs/plugins/updater/self-hosted/manual-update/) ## Install Capacitor updater [Section titled “Install Capacitor updater”](#install-capacitor-updater) Install the Capacitor updater ```bash npm install @capgo/capacitor-updater npx cap sync ``` ## Prepare your bundle [Section titled “Prepare your bundle”](#prepare-your-bundle) To send updates to your app, you need to zip it. The best way to be certain your zip is good is to use the Capgo CLI for zipping. Create a bundle with your files to serve from your server ```bash npx @capgo/cli@latest bundle zip ``` You will have to serve this zip from your server on your own. [Auto Update ](/docs/plugins/updater/self-hosted/auto-update/) [Manual ](/docs/plugins/updater/self-hosted/manual-update/) Note If this seems like a lot of work, try the trial Capgo Cloud. Note Delta (manifest) updates will not work in manual updates, but they can work in auto update. Right now it’s not documented because it’s a pretty complex process. # Channel API Endpoint > How to build channel management endpoints for self-hosted Capgo to handle device-channel assignments and channel queries Channels are a core mechanism for managing app updates in Capgo. In self-hosted mode, you need to implement channel endpoints to handle device assignments, channel queries, and channel management operations. ## Understanding Channels [Section titled “Understanding Channels”](#understanding-channels) Channels allow you to: * **Control update distribution**: Assign different app versions to different user groups * **A/B testing**: Test new features with specific user segments * **Staged rollouts**: Gradually deploy updates to minimize risk * **Environment separation**: Separate development, staging, and production updates ## Configuration [Section titled “Configuration”](#configuration) Configure the channel endpoint URL in your `capacitor.config.json`: ```json { "plugins": { "CapacitorUpdater": { "channelUrl": "https://myserver.com/api/channel_self" } } } ``` ## Channel Operations [Section titled “Channel Operations”](#channel-operations) The plugin performs different channel operations that your endpoint needs to handle: ### 1. List Compatible Channels (GET Request) [Section titled “1. List Compatible Channels (GET Request)”](#1-list-compatible-channels-get-request) When the plugin calls `listChannels()`, it sends a GET request to retrieve all channels that are compatible with the device. This returns channels that match the device’s environment (dev/prod, emulator/real device) and allow either public access or self-assignment. #### Request Format [Section titled “Request Format”](#request-format) ```typescript // GET /api/channel_self // Headers: { "Content-Type": "application/json" } // Query parameters: interface ListChannelsRequest { app_id: string platform: "ios" | "android" | "electron" is_emulator: boolean is_prod: boolean key_id?: string } ``` #### Response Format [Section titled “Response Format”](#response-format) ```json [ { "id": 1, "name": "production", "public": true, "allow_self_set": false }, { "id": 2, "name": "beta", "public": false, "allow_self_set": true } ] ``` #### Understanding Channel Types [Section titled “Understanding Channel Types”](#understanding-channel-types) The response includes two important flags for each channel: * **`public: true`**: This is a **default channel**. Devices cannot self-assign to it using `setChannel()`. Instead, if a device removes its channel assignment (using `unsetChannel()`), it will automatically receive updates from this public channel if it matches the device’s conditions. * **`allow_self_set: true`**: This is a **self-assignable channel**. Devices can explicitly assign themselves to this channel using `setChannel()`. This is useful for beta testing, A/B testing, or allowing users to opt-in to specific update tracks. Note A channel can be either `public` OR `allow_self_set`, but typically not both. Public channels serve as the default fallback, while self-assignable channels require explicit opt-in. ### 2. Get Channel (PUT Request) [Section titled “2. Get Channel (PUT Request)”](#2-get-channel-put-request) When the plugin calls `getChannel()`, it sends a PUT request to retrieve the device’s current channel assignment. #### Request Format [Section titled “Request Format”](#request-format-1) ```typescript // PUT /api/channel_self // Headers: { "Content-Type": "application/json" } // Body: interface GetChannelRequest { device_id: string app_id: string platform: "ios" | "android" | "electron" plugin_version: string version_build: string version_code: string version_name: string is_emulator: boolean is_prod: boolean defaultChannel?: string channel?: string // For newer plugin versions, contains local channel override } ``` #### Response Format [Section titled “Response Format”](#response-format-1) ```json { "status": "ok", "channel": "production", "allowSet": true, "message": "", "error": "" } ``` ### 3. Set Channel (POST Request) [Section titled “3. Set Channel (POST Request)”](#3-set-channel-post-request) When the plugin calls `setChannel()`, it sends a POST request to assign the device to a specific channel. #### Request Format [Section titled “Request Format”](#request-format-2) ```typescript // POST /api/channel_self interface SetChannelRequest { device_id: string app_id: string channel: string platform: "ios" | "android" | "electron" plugin_version: string version_build: string version_code: string version_name: string is_emulator: boolean is_prod: boolean } ``` #### Response Format [Section titled “Response Format”](#response-format-2) ```json { "status": "ok", "message": "Device assigned to channel successfully", "error": "" } ``` #### Error Cases [Section titled “Error Cases”](#error-cases) When a device tries to assign itself to a **public channel** (one with `public: true`), your endpoint should return an error: ```json { "status": "error", "error": "public_channel_self_set_not_allowed", "message": "This channel is public and does not allow device self-assignment. Unset the channel and the device will automatically use the public channel." } ``` When a device tries to assign itself to a channel that doesn’t allow self-assignment: ```json { "status": "error", "error": "channel_self_set_not_allowed", "message": "This channel does not allow devices to self associate" } ``` ### 4. Unset Channel (DELETE Request) [Section titled “4. Unset Channel (DELETE Request)”](#4-unset-channel-delete-request) When the plugin calls `unsetChannel()`, it sends a DELETE request to remove the device’s channel assignment. #### Request Format [Section titled “Request Format”](#request-format-3) ```typescript // DELETE /api/channel_self interface UnsetChannelRequest { device_id: string app_id: string platform: "ios" | "android" | "electron" plugin_version: string version_build: string version_code: string version_name: string } ``` ## Implementation Example [Section titled “Implementation Example”](#implementation-example) Here’s a JavaScript example of how to implement the channel endpoint: ```typescript interface ChannelRequest { device_id: string app_id: string channel?: string platform: "ios" | "android" | "electron" plugin_version: string version_build: string version_code: string version_name: string } interface ChannelResponse { status: "ok" | "error" channel?: string allowSet?: boolean message?: string error?: string } export const handler = async (event) => { const method = event.httpMethod || event.method const body = JSON.parse(event.body || '{}') as ChannelRequest const { device_id, app_id, channel, platform } = body try { switch (method) { case 'GET': return await getDeviceChannel(device_id, app_id) case 'POST': return await setDeviceChannel(device_id, app_id, channel!, platform) case 'DELETE': return await unsetDeviceChannel(device_id, app_id) default: return { status: "error", error: "Method not allowed" } } } catch (error) { return { status: "error", error: error.message } } } async function getDeviceChannel(deviceId: string, appId: string): Promise<ChannelResponse> { // Query your database for device channel assignment const assignment = await database.getDeviceChannel(deviceId, appId) if (assignment) { return { status: "ok", channel: assignment.channel, allowSet: assignment.allowSelfAssign } } // Return default channel if no assignment found return { status: "ok", channel: "production", // Your default channel allowSet: true } } async function setDeviceChannel( deviceId: string, appId: string, channel: string, platform: string ): Promise<ChannelResponse> { // Validate channel exists and allows self-assignment const channelConfig = await database.getChannelConfig(channel, appId) if (!channelConfig) { return { status: "error", error: "Channel not found" } } if (!channelConfig.allowDeviceSelfSet) { return { status: "error", error: "Channel does not allow self-assignment" } } // Check platform restrictions if (platform === "ios" && !channelConfig.ios) { return { status: "error", error: "Channel not available for iOS" } } if (platform === "android" && !channelConfig.android) { return { status: "error", error: "Channel not available for Android" } } if (platform === "electron" && !channelConfig.electron) { return { status: "error", error: "Channel not available for Electron" } } // Save the assignment await database.setDeviceChannel(deviceId, appId, channel) return { status: "ok", message: "Device assigned to channel successfully" } } async function unsetDeviceChannel(deviceId: string, appId: string): Promise<ChannelResponse> { // Remove device channel assignment await database.removeDeviceChannel(deviceId, appId) return { status: "ok", message: "Device channel assignment removed" } } ``` ## Channel Configuration [Section titled “Channel Configuration”](#channel-configuration) Your channel system should support these configuration options: ```typescript interface ChannelConfig { name: string appId: string // Platform targeting ios: boolean // Allow updates to iOS devices android: boolean // Allow updates to Android devices electron: boolean // Allow updates to Electron apps // Device type restrictions allow_emulator: boolean // Allow updates on emulator/simulator devices allow_device: boolean // Allow updates on real/physical devices // Build type restrictions allow_dev: boolean // Allow updates on development builds (is_prod=false) allow_prod: boolean // Allow updates on production builds (is_prod=true) // Channel assignment public: boolean // Default channel - devices fall back to this when no override allowDeviceSelfSet: boolean // Allow devices to self-assign via setChannel() // Update policies disableAutoUpdate: "major" | "minor" | "version_number" | "none" disableAutoUpdateUnderNative: boolean } ``` ### Device Filtering Logic [Section titled “Device Filtering Logic”](#device-filtering-logic) When listing compatible channels (GET request), you should filter channels based on these conditions: 1. **Platform check**: Channel must allow the device’s platform (`ios`, `android`, or `electron`) 2. **Device type check**: * If `is_emulator=true`: Channel must have `allow_emulator=true` * If `is_emulator=false`: Channel must have `allow_device=true` 3. **Build type check**: * If `is_prod=true`: Channel must have `allow_prod=true` * If `is_prod=false`: Channel must have `allow_dev=true` 4. **Visibility check**: Channel must be either `public=true` OR `allow_device_self_set=true` ```typescript // Example filtering logic function getCompatibleChannels( platform: 'ios' | 'android' | 'electron', isEmulator: boolean, isProd: boolean, channels: ChannelConfig[] ): ChannelConfig[] { return channels.filter(channel => { // Platform check if (!channel[platform]) return false // Device type check if (isEmulator && !channel.allow_emulator) return false if (!isEmulator && !channel.allow_device) return false // Build type check if (isProd && !channel.allow_prod) return false if (!isProd && !channel.allow_dev) return false // Must be accessible (public or self-assignable) if (!channel.public && !channel.allowDeviceSelfSet) return false return true }) } ``` ## Database Schema Example [Section titled “Database Schema Example”](#database-schema-example) You’ll need to store channel configurations and device assignments: ```sql -- Channels table CREATE TABLE channels ( id SERIAL PRIMARY KEY, name VARCHAR(255) NOT NULL, app_id VARCHAR(255) NOT NULL, -- Platform targeting ios BOOLEAN DEFAULT true, android BOOLEAN DEFAULT true, electron BOOLEAN DEFAULT true, -- Device type restrictions allow_emulator BOOLEAN DEFAULT true, -- Allow emulator/simulator devices allow_device BOOLEAN DEFAULT true, -- Allow real/physical devices -- Build type restrictions allow_dev BOOLEAN DEFAULT true, -- Allow development builds allow_prod BOOLEAN DEFAULT true, -- Allow production builds -- Channel assignment public BOOLEAN DEFAULT false, -- Default channel (fallback) allow_device_self_set BOOLEAN DEFAULT false, -- Allow self-assignment -- Update policies disable_auto_update VARCHAR(50) DEFAULT 'none', disable_auto_update_under_native BOOLEAN DEFAULT false, created_at TIMESTAMP DEFAULT NOW(), UNIQUE(name, app_id) ); -- Device channel assignments table CREATE TABLE device_channels ( id SERIAL PRIMARY KEY, device_id VARCHAR(255) NOT NULL, app_id VARCHAR(255) NOT NULL, channel_name VARCHAR(255) NOT NULL, assigned_at TIMESTAMP DEFAULT NOW(), UNIQUE(device_id, app_id) ); ``` ## Error Handling [Section titled “Error Handling”](#error-handling) Handle common error scenarios: ```typescript // Channel not found { "status": "error", "error": "Channel 'beta' not found" } // Self-assignment not allowed { "status": "error", "error": "Channel does not allow device self-assignment" } // Platform not supported { "status": "error", "error": "Channel not available for this platform" } // Invalid request { "status": "error", "error": "Missing required field: device_id" } ``` ## Best Practices [Section titled “Best Practices”](#best-practices) 1. **Security**: Validate all channel assignments against your business rules 2. **Logging**: Log all channel operations for auditing and debugging 3. **Performance**: Cache channel configurations to reduce database queries 4. **Validation**: Verify device\_id and app\_id authenticity 5. **Rate Limiting**: Implement rate limiting to prevent abuse ## Integration with Updates [Section titled “Integration with Updates”](#integration-with-updates) Channel assignments work together with your [Update API Endpoint](/docs/plugins/updater/self-hosted/handling-updates/). When a device requests an update, check its channel assignment to determine which version to serve: ```typescript async function getUpdateForDevice(deviceId: string, appId: string) { // Get device's channel assignment const channelAssignment = await getDeviceChannel(deviceId, appId) const channel = channelAssignment.channel || 'production' // Get the version assigned to this channel const channelVersion = await getChannelVersion(channel, appId) return { version: channelVersion.version, url: channelVersion.url, checksum: channelVersion.checksum } } ``` This creates a complete self-hosted channel management system that gives you full control over how updates are distributed to your users. # Statistics API > How to use the statistics endpoint of Capgo with the auto-update plugin in self-hosted mode, what they are used for and what to expect ## Statistics API [Section titled “Statistics API”](#statistics-api) Starting from version 1.3.0 the update system is able to send stats! By default, all stats are sent to our server, to understand usage and research. Note No private data is sent for stats, only random UUID, version update, version native app, platform, action, and app ID. If you want to send this data to your server instead, change the config below: ```tsx // capacitor.config.json { "appId": "**.***.**", "appName": "Name", "plugins": { "CapacitorUpdater": { "statsUrl": "YOUR_URL" } } } ``` ## Data Structure [Section titled “Data Structure”](#data-structure) What your server will receive is: ```tsx interface AppInfosStats { "action": "set", // can be set, delete, set_fail, reset, revert // Then it's the same info as update "app_id": "**.***.**", // app identifier in the store "device_id": "*******", // unique id per app install "platform": "ios", // or android, or electron "custom_id": "user_1", // represent your user "version_name": "1.2.3", // version of the web build "version_build": "1.2.0", // version of the native build "version_code": "120", // build number of the native build "version_os": "16", // OS version of the device "plugin_version": "4.0.0"// to make your api behave differently with different plugins "is_emulator": false, "is_prod": false, } ``` You can also totally disable it, with an empty string. Keep in mind, statistics are made private friendly and help me to understand how people use the plugin, to resolve issues and improve it. ## Expected “no update” behavior [Section titled “Expected “no update” behavior”](#expected-no-update-behavior) When your update endpoint has **no new version**, it should respond with an error payload like: ```json { "error": "no_new_version_available", "message": "No new version available" } ``` The `error` code must be exactly `no_new_version_available`. The `message` can be any string you want (it’s only for logging/debugging). This is the expected behavior and it is still returned with HTTP `200`. If your update endpoint instead returns a `200` response without a `url`, the plugin will treat it as a download failure and send a `download_fail` stat. ## Implementation Example [Section titled “Implementation Example”](#implementation-example) Here is an example of code in JavaScript to save the stats of the plugin: ```typescript interface AppInfos { version_name: string action: 'ping' | 'delete' | 'reset' | 'set' | 'get' | 'set_fail' | 'update_fail' | 'download_fail' | 'windows_path_fail' | 'canonical_path_fail' | 'directory_path_fail' | 'unzip_fail' | 'low_mem_fail' | 'download_10' | 'download_20' | 'download_30' | 'download_40' | 'download_50' | 'download_60' | 'download_70' | 'download_80' | 'download_90' | 'download_complete' | 'download_manifest_start' | 'download_manifest_complete' | 'download_zip_start' | 'download_zip_complete' | 'download_manifest_file_fail' | 'download_manifest_checksum_fail' | 'download_manifest_brotli_fail' | 'decrypt_fail' | 'app_moved_to_foreground' | 'app_moved_to_background' | 'uninstall' | 'needPlanUpgrade' | 'missingBundle' | 'noNew' | 'disablePlatformIos' | 'disablePlatformAndroid' | 'disableAutoUpdateToMajor' | 'cannotUpdateViaPrivateChannel' | 'disableAutoUpdateToMinor' | 'disableAutoUpdateToPatch' | 'channelMisconfigured' | 'disableAutoUpdateMetadata' | 'disableAutoUpdateUnderNative' | 'disableDevBuild' | 'disableEmulator' | 'cannotGetBundle' | 'checksum_fail' | 'NoChannelOrOverride' | 'setChannel' | 'getChannel' | 'rateLimited' | 'disableAutoUpdate' | 'InvalidIp' | 'keyMismatch' | 'blocked_by_server_url' version_build: string version_code: string version_os: string plugin_version: string platform: string app_id: string device_id: string custom_id?: string is_prod?: boolean is_emulator?: boolean } export const handler: Handler = async (event) => { const body = JSON.parse(event.body || '{}') as AppInfos const { platform, app_id, action, version_code, version_os, device_id, version_name, version_build, plugin_version, } = body console.log('update asked', platform, app_id, action, version_os, version_code, device_id, version_name, version_build, plugin_version) // Save it in your database return { status: 'ok' } } ``` This endpoint should return a JSON: ```json { "status": "ok" } ``` ## Actions [Section titled “Actions”](#actions) For detailed descriptions of all action codes and their meanings, please refer to the debugging documentation: * **Actions sent from the device**: See the [debugging documentation - Sent from the device](/docs/plugins/updater/debugging/#sent-from-the-device) section * **Actions sent from the backend**: See the [debugging documentation - Sent from the backend](/docs/plugins/updater/debugging/#sent-from-the-backend) section [Handling Updates ](/docs/plugins/updater/self-hosted/handling-updates/) # Update API Endpoint > How to build your update server API endpoint to respond to Capgo plugin requests with proper bundle information and checksums Here is an example of code in JavaScript to send an update to the plugin ```typescript interface AppInfos { version_name: string version_build: string version_os: string custom_id?: string is_prod?: boolean is_emulator?: boolean plugin_version: string platform: string app_id: string device_id: string } export const handler: Handler = async (event) => { const body = JSON.parse(event.body || '{}') as AppInfos const { platform, app_id, version_os, device_id, version_name, version_build, plugin_version, } = body console.log('update asked', platform, app_id, version_os, device_id, version_name, version_build, plugin_version) if (version_name === '1.0.0') { return { version: '1.0.1', url: 'https://apiurl.com/mybuild_101.zip', checksum: 'sha256_checksum_of_bundle', } } else if (version_name === '1.0.1') { return { version: '1.0.2', url: 'https://apiurl.com/mybuild_102.zip', checksum: 'sha256_checksum_of_bundle', } } else { return { message: 'Error version not found' version: '', url: '', } } } ``` ## Response Format [Section titled “Response Format”](#response-format) For **non-encrypted bundles**, your endpoint should return: ```json { "version": "1.0.2", "url": "https://apiurl.com/mybuild_102.zip", "checksum": "sha256_checksum_of_bundle" } ``` For **encrypted bundles**, you also need to include the session key: ```json { "version": "1.0.2", "url": "https://apiurl.com/mybuild_102.zip", "checksum": "encrypted_checksum_from_encrypt_command", "session_key": "ivSessionKey_from_encrypt_command" } ``` And if no update or error, add the `message` key and optionally an `error`: ```json { "message": "Version not found", "error": "The backend crashed", "version": "1.0.2", } ``` ## Field Descriptions [Section titled “Field Descriptions”](#field-descriptions) * **`checksum`**: SHA256 hash of your bundle zip file for integrity verification * **`session_key`**: Required only for encrypted bundles - this is the `ivSessionKey` returned by the encrypt command * **`version`**: Version identifier in semver format * **`url`**: HTTPS URL where the bundle can be downloaded ## Bundle Creation [Section titled “Bundle Creation”](#bundle-creation) To learn how to create compatible bundles and generate checksums, see the [Auto Update documentation](/docs/plugins/updater/self-hosted/auto-update/#generating-bundle-checksum). For encrypted bundles, see the [Encrypted Bundles documentation](/docs/plugins/updater/self-hosted/encrypted-bundles/) which explains the complete encryption workflow. # Manual Update > A detailed guide on utilizing the manual update plugin within a self-hosted environment, providing comprehensive instructions on configuration and usage to effectively manage updates without relying on automatic processes. ## Configuration [Section titled “Configuration”](#configuration) Add this to your `capacitor.config.json`, to disable auto-update. ```tsx // capacitor.config.json { "appId": "**.***.**", "appName": "Name", "plugins": { "CapacitorUpdater": { "autoUpdate": false, } } } ``` ## Usage [Section titled “Usage”](#usage) You can use this example or re-create the logic in your app. Caution We are forcing the user to update the app with a static version declared in the code. This is not recommended, you should use a dynamic version from your server. Danger We are not doing any version checking, decryption or checksum validation in this example. You should do that on your own. ```tsx import { CapacitorUpdater } from '@capgo/capacitor-updater' import { SplashScreen } from '@capacitor/splash-screen' import { App } from '@capacitor/app' let data = {version: ""} CapacitorUpdater.notifyAppReady() App.addListener('appStateChange', async(state) => { if (state.isActive) { // Do the download during user active app time to prevent failed download data = await CapacitorUpdater.download({ version: '0.0.4', url: 'https://github.com/Cap-go/demo-app/releases/download/0.0.4/dist.zip', }) } if (!state.isActive && data.version !== "") { // Do the switch when user leave app SplashScreen.show() try { await CapacitorUpdater.set(data) } catch (err) { console.log(err) SplashScreen.hide() // in case the set fail, otherwise the new app will have to hide it } } }) ``` Note If this seems like a lot of work consider trying [Capgo trial](https://capgo.app/register/). It will handle all of this for you. # Settings > All available settings for Capacitor Updater, all the configuration you can set in you capacitor config and what they used for To have more fine-grained control over the update system, you can configure it with these settings: Tip Any changes to these settings in capacitor.config file, require syncing the platform and releasing to the store for production apps to receive them. ## `allowModifyUrl` [Section titled “allowModifyUrl”](#allowmodifyurl) > Allow the plugin to modify the updateUrl, statsUrl and channelUrl dynamically from the JavaScript side. Available on Android, iOS, and Electron. Default: `false` capacitor.config.json ```json { "plugins": { "CapacitorUpdater": { "allowModifyUrl": true } } } ``` ## `appId` [Section titled “appId”](#appid) > Configure the app id for the app in the config. Available on Android, iOS, and Electron. Default: `undefined` capacitor.config.json ```json { "plugins": { "CapacitorUpdater": { "appId": "com.example.app" } } } ``` ## `appReadyTimeout` [Section titled “appReadyTimeout”](#appreadytimeout) > Configure the number of milliseconds the native plugin should wait before considering an update ‘failed’. Available on Android, iOS, and Electron. Default: `10000` (10 seconds) capacitor.config.json ```json { "plugins": { "CapacitorUpdater": { "appReadyTimeout": 1000 } } } ``` ## `autoDeleteFailed` [Section titled “autoDeleteFailed”](#autodeletefailed) > Configure whether the plugin should automatically delete failed bundles. Available on Android, iOS, and Electron. Default: `true` capacitor.config.json ```json { "plugins": { "CapacitorUpdater": { "autoDeleteFailed": false } } } ``` ## `autoDeletePrevious` [Section titled “autoDeletePrevious”](#autodeleteprevious) > Configure whether the plugin should automatically delete previous bundles after a successful update. Available on Android, iOS, and Electron. Default: `true` capacitor.config.json ```json { "plugins": { "CapacitorUpdater": { "autoDeletePrevious": false } } } ``` ## `autoSplashscreen` [Section titled “autoSplashscreen”](#autosplashscreen) > Automatically handle splashscreen hiding when using directUpdate. When enabled, the plugin will automatically hide the splashscreen after updates are applied or when no update is needed. This removes the need to manually listen for appReady events and call SplashScreen.hide(). Only works when directUpdate is set to “atInstall”, “always”, or true. Requires the @capacitor/splash-screen plugin to be installed and configured with launchAutoHide: false. Requires autoUpdate and directUpdate to be enabled. Available on Android, iOS, and Electron. Default: `false` capacitor.config.json ```json { "plugins": { "CapacitorUpdater": { "autoUpdate": true, "directUpdate": "atInstall", "autoSplashscreen": true } } } ``` ## `autoUpdate` [Section titled “autoUpdate”](#autoupdate) > Configure whether the plugin should use Auto Update via an update server. Available on Android, iOS, and Electron. Default: `true` capacitor.config.json ```json { "plugins": { "CapacitorUpdater": { "autoUpdate": false } } } ``` ## `channelUrl` [Section titled “channelUrl”](#channelurl) > Configure the URL / endpoint for channel operations. Available on Android, iOS, and Electron. Default: `https://plugin.capgo.app/channel_self` capacitor.config.json ```json { "plugins": { "CapacitorUpdater": { "channelUrl": "https://example.com/api/channel" } } } ``` ## `defaultChannel` [Section titled “defaultChannel”](#defaultchannel) > Set the default channel for the app in the config. Case sensitive. This setting will override the default channel set in the cloud, but will still respect overrides made in the cloud. Available on Android, iOS, and Electron. Default: `undefined` capacitor.config.json ```json { "plugins": { "CapacitorUpdater": { "defaultChannel": "production" } } } ``` ## `directUpdate` [Section titled “directUpdate”](#directupdate) > Configure when the plugin should direct install updates. Only for autoUpdate mode. Works well for apps less than 10MB and with uploads done using the —delta flag. Zip or apps more than 10MB will be relatively slow for users to update. Options: * `false`: Never do direct updates (use default behavior: download at start, set when backgrounded) * `'atInstall'`: Direct update only when app is installed, updated from store, otherwise act as directUpdate = false * `'onLaunch'`: Direct update only on app installed, updated from store or after app kill, otherwise act as directUpdate = false * `'always'`: Direct update in all previous cases (app installed, updated from store, after app kill or app resume), never act as directUpdate = false * `true`: (deprecated) Same as “always” for backward compatibility Available on Android, iOS, and Electron. Default: `false` capacitor.config.json ```json { "plugins": { "CapacitorUpdater": { "autoUpdate": true, "directUpdate": "atInstall" } } } ``` ## `disableJSLogging` [Section titled “disableJSLogging”](#disablejslogging) > Disable the JavaScript logging of the plugin. If true, the plugin will not log to the JavaScript console. Only the native log will be done. Available on Android, iOS, and Electron. Default: `false` capacitor.config.json ```json { "plugins": { "CapacitorUpdater": { "disableJSLogging": true } } } ``` ## `keepUrlPathAfterReload` [Section titled “keepUrlPathAfterReload”](#keepurlpathafterreload) > Configure the plugin to keep the URL path after a reload. Caution When a reload is triggered, ‘window\.history’ will be cleared. Available on Android, iOS, and Electron. Default: `false` capacitor.config.json ```json { "plugins": { "CapacitorUpdater": { "keepUrlPathAfterReload": true } } } ``` ## `periodCheckDelay` [Section titled “periodCheckDelay”](#periodcheckdelay) > Configure the delay period for period update check. The unit is in seconds. Cannot be less than 600 seconds (10 minutes). Available on Android, iOS, and Electron. Default: `600` (10 minutes) capacitor.config.json ```json { "plugins": { "CapacitorUpdater": { "periodCheckDelay": 600 // (10 minutes) } } } ``` ## `publicKey` [Section titled “publicKey”](#publickey) > Configure the public key for end to end live update encryption Version 2. Available on Android, iOS, and Electron. Default: `undefined` capacitor.config.json ```json { "plugins": { "CapacitorUpdater": { "publicKey": "YOUR_PUBLIC_KEY" } } } ``` ## `resetWhenUpdate` [Section titled “resetWhenUpdate”](#resetwhenupdate) > Automatically delete previous downloaded bundles when a newer native app bundle is installed to the device. Available on Android, iOS, and Electron. Default: `true` capacitor.config.json ```json { "plugins": { "CapacitorUpdater": { "resetWhenUpdate": false } } } ``` ## `responseTimeout` [Section titled “responseTimeout”](#responsetimeout) > Configure the number of milliseconds the native plugin should wait before considering API timeout. Available on Android, iOS, and Electron. Default: `20` (20 seconds) capacitor.config.json ```json { "plugins": { "CapacitorUpdater": { "responseTimeout": 10 // (10 seconds) } } } ``` ## `shakeMenu` [Section titled “shakeMenu”](#shakemenu) > Enable shake gesture to show update menu for debugging/testing purposes. Available on Android, iOS, and Electron. Default: `false` capacitor.config.json ```json { "plugins": { "CapacitorUpdater": { "shakeMenu": true } } } ``` ## `statsUrl` [Section titled “statsUrl”](#statsurl) > Configure the URL / endpoint to which update statistics are sent. Available on Android, iOS, and Electron. Set to "" to disable stats reporting. Default: `https://plugin.capgo.app/stats` capacitor.config.json ```json { "plugins": { "CapacitorUpdater": { "statsUrl": "https://example.com/api/stats" } } } ``` ## `updateUrl` [Section titled “updateUrl”](#updateurl) > Configure the URL / endpoint to which update checks are sent. Available on Android, iOS, and Electron. Default: `https://plugin.capgo.app/updates` capacitor.config.json ```json { "plugins": { "CapacitorUpdater": { "updateUrl": "https://example.com/api/auto_update" } } } ``` ## `version` [Section titled “version”](#version) > Configure the current version of the app. This will be used for the first update request. If not set, the plugin will get the version from the native code. Available on Android, iOS, and Electron. Default: `undefined` capacitor.config.json ```json { "plugins": { "CapacitorUpdater": { "version": "1.0.0" } } } ``` ## Development Settings [Section titled “Development Settings”](#development-settings) ### `localApi` [Section titled “localApi”](#localapi) > Configure the CLI to use a local api for testing. Default: `undefined` capacitor.config.json ```json { "plugins": { "CapacitorUpdater": { "localApi": "http://localhost:54321/functions/v1" } } } ``` ### `localApiFiles` [Section titled “localApiFiles”](#localapifiles) > Configure the CLI to use a local file api for testing. Default: `undefined` capacitor.config.json ```json { "plugins": { "CapacitorUpdater": { "localApiFiles": "http://localhost:54321/functions/v1/files" } } } ``` ### `localHost` [Section titled “localHost”](#localhost) > Configure the CLI to use a local server for testing or self-hosted update server. Default: `undefined` capacitor.config.json ```json { "plugins": { "CapacitorUpdater": { "localHost": "http://localhost:5173" } } } ``` ### `localSupa` [Section titled “localSupa”](#localsupa) > Configure the CLI to use a local server for testing or self-hosted update server. Default: `undefined` capacitor.config.json ```json { "plugins": { "CapacitorUpdater": { "localSupa": "http://localhost:54321" } } } ``` ### `localSupaAnon` [Section titled “localSupaAnon”](#localsupaanon) > Configure the CLI to use a local server for testing. Default: `undefined` capacitor.config.json ```json { "plugins": { "CapacitorUpdater": { "localSupaAnon": "YOUR_LOCAL_ANON_KEY" } } } ``` ### `localWebHost` [Section titled “localWebHost”](#localwebhost) > Configure the CLI to use a local server for testing or self-hosted update server. Default: `undefined` capacitor.config.json ```json { "plugins": { "CapacitorUpdater": { "localWebHost": "http://localhost:5173" } } } ``` Tip There are additional settings available in the [Capgo web app](https://console.capgo.app/login) that can be configured per channel without requiring a native app release. # @capgo/capacitor-uploader > Capacitor Uploader Plugin for uploading files with background support and progress tracking. ## Overview [Section titled “Overview”](#overview) Capacitor Uploader Plugin for uploading files with background support and progress tracking. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `startUpload` - Start uploading a file to a server. * `removeUpload` - Cancel and remove an ongoing upload. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------ | --------------------------------------------- | | `startUpload` | Start uploading a file to a server. | | `removeUpload` | Cancel and remove an ongoing upload. | | `addListener` | Listen for upload progress and status events. | | `getPluginVersion` | Get the native Capacitor plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-uploader](https://github.com/Cap-go/capacitor-uploader/). # Getting Started > Install @capgo/capacitor-uploader and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-uploader bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { Uploader } from '@capgo/capacitor-uploader'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `startUpload` [Section titled “startUpload”](#startupload) Start uploading a file to a server. The upload will continue in the background even if the app is closed or backgrounded. Listen to upload events to track progress, completion, or failure. ```typescript import { Uploader } from '@capgo/capacitor-uploader'; const { id } = await Uploader.startUpload({ filePath: 'file:///path/to/file.jpg', serverUrl: 'https://example.com/upload', headers: { 'Authorization': 'Bearer token' }, method: 'POST', uploadType: 'multipart', fileField: 'photo' }); console.log('Upload started with ID:', id); ``` ### `removeUpload` [Section titled “removeUpload”](#removeupload) Cancel and remove an ongoing upload. This will stop the upload if it’s in progress and clean up resources. ```typescript import { Uploader } from '@capgo/capacitor-uploader'; await Uploader.removeUpload({ id: 'upload-123' }); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `uploadOption` [Section titled “uploadOption”](#uploadoption) Configuration options for uploading a file. ````typescript export interface uploadOption { /** * The local file path of the file to upload. * Can be a file:// URL or an absolute path. * * @since 0.0.1 */ filePath: string; /** * The server URL endpoint where the file should be uploaded. * * @since 0.0.1 */ serverUrl: string; /** * The title of the upload notification shown to the user. * Android only. * * @default 'Uploading' * @since 0.0.1 */ notificationTitle?: string; /** * HTTP headers to send with the upload request. * Useful for authentication tokens, content types, etc. * * @since 0.0.1 * @example * ```typescript * headers: { * 'Authorization': 'Bearer token123', * 'X-Custom-Header': 'value' * } * ``` */ headers: { [key: string]: string; }; /** * The HTTP method to use for the upload request. * * @default 'POST' * @since 0.0.1 */ method?: 'PUT' | 'POST'; /** * The MIME type of the file being uploaded. * If not specified, the plugin will attempt to determine it automatically. * * @since 0.0.1 * @example 'image/jpeg', 'application/pdf', 'video/mp4' */ mimeType?: string; /** * Additional form parameters to send with the upload request. * These will be included as form data in multipart uploads. * * @since 0.0.1 */ parameters?: { [key: string]: string }; /** * The maximum number of times to retry the upload if it fails. * * @since 0.0.1 * @default 0 */ maxRetries?: number; /** * The type of upload to perform. * - 'binary': Uploads the file as raw binary data in the request body * - 'multipart': Uploads the file as multipart/form-data * * @default 'binary' * @since 0.0.2 */ uploadType?: 'binary' | 'multipart'; /** * The form field name for the file when using multipart upload type. * Only used when uploadType is 'multipart'. * * @default 'file' * @since 0.0.2 */ fileField?: string; } ```` ### `UploadEvent` [Section titled “UploadEvent”](#uploadevent) Event emitted during the upload lifecycle. ```typescript export interface UploadEvent { /** * The current status of the upload. * - 'uploading': Upload is in progress * - 'completed': Upload finished successfully * - 'failed': Upload encountered an error * * @since 0.0.1 */ name: 'uploading' | 'completed' | 'failed'; /** * Additional data about the upload event. * * @since 0.0.1 */ payload: { /** * Upload progress percentage from 0 to 100. * Only present during 'uploading' events. * * @since 0.0.1 */ percent?: number; /** * Error message if the upload failed. * Only present during 'failed' events. * * @since 0.0.1 */ error?: string; /** * HTTP status code returned by the server. * Present during 'completed' and 'failed' events. * * @since 0.0.1 */ statusCode?: number; }; /** * Unique identifier for this upload task. * * @since 0.0.1 */ id: string; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-video-player > Capacitor plugin to play video in native player. ## Overview [Section titled “Overview”](#overview) Capacitor plugin to play video in native player. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `initPlayer` - Initialize a video player. * `isPlaying` - Return if a given playerId is playing. * `play` - Play the current video from a given playerId. * `pause` - Pause the current video from a given playerId. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ---------------------------- | ------------------------------------------------------------------------ | | `initPlayer` | Initialize a video player. | | `isPlaying` | Return if a given playerId is playing. | | `play` | Play the current video from a given playerId. | | `pause` | Pause the current video from a given playerId. | | `getDuration` | Get the duration of the current video from a given playerId. | | `getCurrentTime` | Get the current time of the current video from a given playerId. | | `setCurrentTime` | Set the current time to seek the current video to from a given playerId. | | `getVolume` | Get the volume of the current video from a given playerId. | | `setVolume` | Set the volume of the current video to from a given playerId. | | `getMuted` | Get the muted of the current video from a given playerId. | | `setMuted` | Set the muted of the current video to from a given playerId. | | `setRate` | Set the rate of the current video from a given playerId. | | `getRate` | Get the rate of the current video from a given playerId. | | `stopAllPlayers` | Stop all players playing. | | `showController` | Show controller. | | `isControllerIsFullyVisible` | isControllerIsFullyVisible. | | `exitPlayer` | Exit player. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-video-player](https://github.com/Cap-go/capacitor-video-player/). # Getting Started > Install @capgo/capacitor-video-player and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-video-player bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { VideoPlayer } from '@capgo/capacitor-video-player'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `initPlayer` [Section titled “initPlayer”](#initplayer) Initialize a video player ```typescript import { VideoPlayer } from '@capgo/capacitor-video-player'; await VideoPlayer.initPlayer({} as capVideoPlayerOptions); ``` ### `isPlaying` [Section titled “isPlaying”](#isplaying) Return if a given playerId is playing ```typescript import { VideoPlayer } from '@capgo/capacitor-video-player'; await VideoPlayer.isPlaying({} as capVideoPlayerIdOptions); ``` ### `play` [Section titled “play”](#play) Play the current video from a given playerId ```typescript import { VideoPlayer } from '@capgo/capacitor-video-player'; await VideoPlayer.play({} as capVideoPlayerIdOptions); ``` ### `pause` [Section titled “pause”](#pause) Pause the current video from a given playerId ```typescript import { VideoPlayer } from '@capgo/capacitor-video-player'; await VideoPlayer.pause({} as capVideoPlayerIdOptions); ``` ### `getDuration` [Section titled “getDuration”](#getduration) Get the duration of the current video from a given playerId ```typescript import { VideoPlayer } from '@capgo/capacitor-video-player'; await VideoPlayer.getDuration({} as capVideoPlayerIdOptions); ``` ### `getCurrentTime` [Section titled “getCurrentTime”](#getcurrenttime) Get the current time of the current video from a given playerId ```typescript import { VideoPlayer } from '@capgo/capacitor-video-player'; await VideoPlayer.getCurrentTime({} as capVideoPlayerIdOptions); ``` ### `setCurrentTime` [Section titled “setCurrentTime”](#setcurrenttime) Set the current time to seek the current video to from a given playerId ```typescript import { VideoPlayer } from '@capgo/capacitor-video-player'; await VideoPlayer.setCurrentTime({} as capVideoTimeOptions); ``` ### `getVolume` [Section titled “getVolume”](#getvolume) Get the volume of the current video from a given playerId ```typescript import { VideoPlayer } from '@capgo/capacitor-video-player'; await VideoPlayer.getVolume({} as capVideoPlayerIdOptions); ``` ### `setVolume` [Section titled “setVolume”](#setvolume) Set the volume of the current video to from a given playerId ```typescript import { VideoPlayer } from '@capgo/capacitor-video-player'; await VideoPlayer.setVolume({} as capVideoVolumeOptions); ``` ### `getMuted` [Section titled “getMuted”](#getmuted) Get the muted of the current video from a given playerId ```typescript import { VideoPlayer } from '@capgo/capacitor-video-player'; await VideoPlayer.getMuted({} as capVideoPlayerIdOptions); ``` ### `setMuted` [Section titled “setMuted”](#setmuted) Set the muted of the current video to from a given playerId ```typescript import { VideoPlayer } from '@capgo/capacitor-video-player'; await VideoPlayer.setMuted({} as capVideoMutedOptions); ``` ### `setRate` [Section titled “setRate”](#setrate) Set the rate of the current video from a given playerId ```typescript import { VideoPlayer } from '@capgo/capacitor-video-player'; await VideoPlayer.setRate({} as capVideoRateOptions); ``` ### `getRate` [Section titled “getRate”](#getrate) Get the rate of the current video from a given playerId ```typescript import { VideoPlayer } from '@capgo/capacitor-video-player'; await VideoPlayer.getRate({} as capVideoPlayerIdOptions); ``` ### `stopAllPlayers` [Section titled “stopAllPlayers”](#stopallplayers) Stop all players playing ```typescript import { VideoPlayer } from '@capgo/capacitor-video-player'; await VideoPlayer.stopAllPlayers(); ``` ### `showController` [Section titled “showController”](#showcontroller) Show controller ```typescript import { VideoPlayer } from '@capgo/capacitor-video-player'; await VideoPlayer.showController(); ``` ### `isControllerIsFullyVisible` [Section titled “isControllerIsFullyVisible”](#iscontrollerisfullyvisible) isControllerIsFullyVisible ```typescript import { VideoPlayer } from '@capgo/capacitor-video-player'; await VideoPlayer.isControllerIsFullyVisible(); ``` ### `exitPlayer` [Section titled “exitPlayer”](#exitplayer) Exit player ```typescript import { VideoPlayer } from '@capgo/capacitor-video-player'; await VideoPlayer.exitPlayer(); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `capVideoPlayerOptions` [Section titled “capVideoPlayerOptions”](#capvideoplayeroptions) ```typescript export interface capVideoPlayerOptions { /** * Player mode * - "fullscreen" * - "embedded" (Web only) */ mode?: string; /** * The url of the video to play */ url?: string; /** * The url of subtitle associated with the video */ subtitle?: string; /** * The language of subtitle * see https://github.com/libyal/libfwnt/wiki/Language-Code-identifiers */ language?: string; /** * SubTitle Options */ subtitleOptions?: SubTitleOptions; /** * Id of DIV Element parent of the player */ playerId?: string; /** * Initial playing rate */ rate?: number; /** * Exit on VideoEnd (iOS, Android) * default: true */ exitOnEnd?: boolean; /** * Loop on VideoEnd when exitOnEnd false (iOS, Android) * default: false */ loopOnEnd?: boolean; /** * Picture in Picture Enable (iOS, Android) * default: true */ pipEnabled?: boolean; /** * Background Mode Enable (iOS, Android) * default: true */ bkmodeEnabled?: boolean; /** * Show Controls Enable (iOS, Android) * default: true */ showControls?: boolean; /** * Display Mode ["all", "portrait", "landscape"] (iOS, Android) * default: "all" */ displayMode?: string; /** * Component Tag or DOM Element Tag (React app) */ componentTag?: string; /** * Player Width (mode "embedded" only) */ width?: number; /** * Player height (mode "embedded" only) */ height?: number; /** * Headers for the request (iOS, Android) * by Manuel García Marín (https://github.com/PhantomPainX) */ headers?: { [key: string]: string; }; /** * Title shown in the player (Android) * by Manuel García Marín (https://github.com/PhantomPainX) */ title?: string; /** * Subtitle shown below the title in the player (Android) * by Manuel García Marín (https://github.com/PhantomPainX) */ smallTitle?: string; /** * ExoPlayer Progress Bar and Spinner color (Android) * by Manuel García Marín (https://github.com/PhantomPainX) * Must be a valid hex color code * default: #FFFFFF */ accentColor?: string; /** * Chromecast enable/disable (Android) * by Manuel García Marín (https://github.com/PhantomPainX) * default: true */ chromecast?: boolean; /** * Artwork url to be shown in Chromecast player * by Manuel García Marín (https://github.com/PhantomPainX) * default: "" */ artwork?: string; /** * DRM configuration for protected content (iOS: FairPlay, Android: Widevine) */ drm?: DrmOptions; } ``` ### `capVideoPlayerResult` [Section titled “capVideoPlayerResult”](#capvideoplayerresult) ```typescript export interface capVideoPlayerResult { /** * result set to true when successful else false */ result?: boolean; /** * method name */ method?: string; /** * value returned */ value?: any; /** * message string */ message?: string; } ``` ### `capVideoPlayerIdOptions` [Section titled “capVideoPlayerIdOptions”](#capvideoplayeridoptions) ```typescript export interface capVideoPlayerIdOptions { /** * Id of DIV Element parent of the player */ playerId?: string; } ``` ### `capVideoTimeOptions` [Section titled “capVideoTimeOptions”](#capvideotimeoptions) ```typescript export interface capVideoTimeOptions { /** * Id of DIV Element parent of the player */ playerId?: string; /** * Video time value you want to seek to */ seektime?: number; } ``` ### `capVideoVolumeOptions` [Section titled “capVideoVolumeOptions”](#capvideovolumeoptions) ```typescript export interface capVideoVolumeOptions { /** * Id of DIV Element parent of the player */ playerId?: string; /** * Volume value between [0 - 1] */ volume?: number; } ``` ### `capVideoMutedOptions` [Section titled “capVideoMutedOptions”](#capvideomutedoptions) ```typescript export interface capVideoMutedOptions { /** * Id of DIV Element parent of the player */ playerId?: string; /** * Muted value true or false */ muted?: boolean; } ``` ### `capVideoRateOptions` [Section titled “capVideoRateOptions”](#capvideorateoptions) ```typescript export interface capVideoRateOptions { /** * Id of DIV Element parent of the player */ playerId?: string; /** * Rate value */ rate?: number; } ``` ### `SubTitleOptions` [Section titled “SubTitleOptions”](#subtitleoptions) ```typescript export interface SubTitleOptions { /** * Foreground Color in RGBA (default rgba(255,255,255,1) */ foregroundColor?: string; /** * Background Color in RGBA (default rgba(0,0,0,1) */ backgroundColor?: string; /** * Font Size in pixels (default 16) */ fontSize?: number; /** * Get the native Capacitor plugin version * * @returns {Promise<{ id: string }>} an Promise with version for this device * @throws An error if the something went wrong */ getPluginVersion(): Promise<{ version: string }>; } ``` ### `DrmOptions` [Section titled “DrmOptions”](#drmoptions) ```typescript export interface DrmOptions { /** * FairPlay DRM configuration (iOS) */ fairplay?: FairPlayDrmOptions; /** * PlayReady DRM configuration */ playready?: PlayreadyDrmOptions; /** * Widevine DRM configuration (Android) */ widevine?: WidevineDrmOptions; } ``` ### `FairPlayDrmOptions` [Section titled “FairPlayDrmOptions”](#fairplaydrmoptions) ```typescript export interface FairPlayDrmOptions { /** * The URL to fetch the FairPlay certificate */ certificateUrl?: string; /** * The URL to send the SPC and receive the CKC license (FairPlay license server URL) */ contentKeySpcUrl?: string; } ``` ### `PlayreadyDrmOptions` [Section titled “PlayreadyDrmOptions”](#playreadydrmoptions) ```typescript export interface PlayreadyDrmOptions { /** * The URL to fetch the PlayReady license */ certificateUrl?: string; } ``` ### `WidevineDrmOptions` [Section titled “WidevineDrmOptions”](#widevinedrmoptions) ```typescript export interface WidevineDrmOptions { /** * The URL to fetch the Widevine license */ certificateUrl?: string; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-video-thumbnails > Capacitor Video Thumbnails Plugin interface for generating video thumbnails. ## Overview [Section titled “Overview”](#overview) Capacitor Video Thumbnails Plugin interface for generating video thumbnails. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `getThumbnail` - Generate a thumbnail image from a video file at a specific time position. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------ | ------------------------------------------------------------------------- | | `getThumbnail` | Generate a thumbnail image from a video file at a specific time position. | | `getPluginVersion` | Get the native Capacitor plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-video-thumbnails](https://github.com/Cap-go/capacitor-video-thumbnails/). # Getting Started > Install @capgo/capacitor-video-thumbnails and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-video-thumbnails bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { CapgoVideoThumbnails } from '@capgo/capacitor-video-thumbnails'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `getThumbnail` [Section titled “getThumbnail”](#getthumbnail) Generate a thumbnail image from a video file at a specific time position. ```typescript import { CapgoVideoThumbnails } from '@capgo/capacitor-video-thumbnails'; const result = await CapgoVideoThumbnails.getThumbnail({ sourceUri: 'file:///path/to/video.mp4', time: 5000, quality: 0.8 }); console.log('Thumbnail URI:', result.uri); console.log('Dimensions:', result.width, 'x', result.height); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `VideoThumbnailsOptions` [Section titled “VideoThumbnailsOptions”](#videothumbnailsoptions) Options for generating a video thumbnail. ```typescript export interface VideoThumbnailsOptions { /** * The URI of the video file. Can be a local file path or a remote URL. * For local files, use file:// protocol or absolute path. * For remote files, use http:// or https:// protocol. */ sourceUri: string; /** * The time position in milliseconds from which to extract the thumbnail. * Defaults to 0 (first frame). */ time?: number; /** * Quality of the generated image, from 0.0 (lowest) to 1.0 (highest). * Defaults to 1.0. */ quality?: number; /** * HTTP headers to include when fetching remote video URIs. * Only applicable for remote URLs. */ headers?: Record<string, string>; } ``` ### `VideoThumbnailsResult` [Section titled “VideoThumbnailsResult”](#videothumbnailsresult) Result of thumbnail generation. ```typescript export interface VideoThumbnailsResult { /** * The local URI path to the generated thumbnail image. * This can be used directly in img tags or Image components. */ uri: string; /** * Width of the generated thumbnail in pixels. */ width: number; /** * Height of the generated thumbnail in pixels. */ height: number; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-volume-buttons > Capacitor Volume Buttons Plugin for detecting hardware volume button presses. ## Overview [Section titled “Overview”](#overview) Capacitor Volume Buttons Plugin for detecting hardware volume button presses. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `addListener` - Listen for presses on the hardware volume buttons. * `removeAllListeners` - Removes all listeners for this plugin. * `getPluginVersion` - Get the native Capacitor plugin version. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | -------------------- | -------------------------------------------------- | | `addListener` | Listen for presses on the hardware volume buttons. | | `removeAllListeners` | Removes all listeners for this plugin. | | `getPluginVersion` | Get the native Capacitor plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-volume-buttons](https://github.com/Cap-go/capacitor-volume-buttons/). # Getting Started > Install @capgo/capacitor-volume-buttons and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-volume-buttons bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { VolumeButtons } from '@capgo/capacitor-volume-buttons'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `addListener` [Section titled “addListener”](#addlistener) Listen for presses on the hardware volume buttons. ```typescript import { VolumeButtons } from '@capgo/capacitor-volume-buttons'; const listener = await VolumeButtons.addListener( 'volumeButtonPressed', (event) => { console.log(`Volume ${event.direction} button pressed`); } ); // Remove listener when done await listener.remove(); ``` ### `removeAllListeners` [Section titled “removeAllListeners”](#removealllisteners) Removes all listeners for this plugin. ```typescript import { VolumeButtons } from '@capgo/capacitor-volume-buttons'; await VolumeButtons.removeAllListeners(); ``` ### `getPluginVersion` [Section titled “getPluginVersion”](#getpluginversion) Get the native Capacitor plugin version. ```typescript import { VolumeButtons } from '@capgo/capacitor-volume-buttons'; const { version } = await VolumeButtons.getPluginVersion(); console.log('Plugin version:', version); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `VolumeButtonListener` [Section titled “VolumeButtonListener”](#volumebuttonlistener) Listener function for volume button events. ```typescript export type VolumeButtonListener = (event: VolumeButtonPressed) => void; ``` ### `VolumeButtonPressed` [Section titled “VolumeButtonPressed”](#volumebuttonpressed) Event data for volume button press. ```typescript export interface VolumeButtonPressed { /** Direction of the button press */ direction: VolumeButtonDirection; } ``` ### `VolumeButtonDirection` [Section titled “VolumeButtonDirection”](#volumebuttondirection) Direction of volume button press. ```typescript export type VolumeButtonDirection = 'up' | 'down'; ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-watch > Apple Watch communication plugin for Capacitor. Provides bidirectional messaging between iPhone and Apple Watch using WatchConnectivity. ## Overview [Section titled “Overview”](#overview) Apple Watch communication plugin for Capacitor. Provides bidirectional messaging between iPhone and Apple Watch using WatchConnectivity. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `sendMessage` - Send an interactive message to the watch. The watch must be reachable for this to succeed. Use this for time-sensitive, interactive communication. * `updateApplicationContext` - Update the application context shared with the watch. Only the latest context is kept - this overwrites any previous context. Use this for syncing app state that the watch needs to display. * `transferUserInfo` - Transfer user info to the watch. Transfers are queued and delivered in order, even if the watch is not currently reachable. Use this for important data that must be delivered reliably. * `replyToMessage` - Reply to a message from the watch that requested a reply. Use this in response to the messageReceivedWithReply event. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `sendMessage` | Send an interactive message to the watch. The watch must be reachable for this to succeed. Use this for time-sensitive, interactive communication. | | `updateApplicationContext` | Update the application context shared with the watch. Only the latest context is kept - this overwrites any previous context. Use this for syncing app state that the watch needs to display. | | `transferUserInfo` | Transfer user info to the watch. Transfers are queued and delivered in order, even if the watch is not currently reachable. Use this for important data that must be delivered reliably. | | `replyToMessage` | Reply to a message from the watch that requested a reply. Use this in response to the messageReceivedWithReply event. | | `getInfo` | Get information about the watch connectivity status. | | `getPluginVersion` | Get the native Capacitor plugin version. | | `addListener` | Listen for messages received from the watch. | | `addListener` | Listen for messages from the watch that require a reply. | | `addListener` | Listen for application context updates from the watch. | | `addListener` | Listen for user info transfers from the watch. | | `addListener` | Listen for watch reachability changes. | | `addListener` | Listen for session activation state changes. | | `removeAllListeners` | Remove all listeners for this plugin. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-watch](https://github.com/Cap-go/capacitor-watch/). # Examples & Use Cases > Real-world examples and patterns for building Apple Watch apps with Capacitor. This guide provides practical examples for common Apple Watch app patterns using `@capgo/capacitor-watch`. ## Example 1: Health & Fitness Tracker [Section titled “Example 1: Health & Fitness Tracker”](#example-1-health--fitness-tracker) Sync workout data between watch and phone. * Watch (SwiftUI) ```swift import SwiftUI import CapgoWatchSDK struct WorkoutView: View { @ObservedObject var connector = WatchConnector.shared @State private var heartRate: Double = 0 @State private var calories: Double = 0 @State private var isTracking = false var body: some View { VStack(spacing: 12) { // Heart Rate Display HStack { Image(systemName: "heart.fill") .foregroundColor(.red) Text("\(Int(heartRate)) BPM") .font(.title2) } // Calories HStack { Image(systemName: "flame.fill") .foregroundColor(.orange) Text("\(Int(calories)) cal") } // Start/Stop Button Button(isTracking ? "Stop" : "Start") { toggleTracking() } .buttonStyle(.borderedProminent) .tint(isTracking ? .red : .green) } .onReceive(Timer.publish(every: 1, on: .main, in: .common).autoconnect()) { _ in if isTracking { updateMetrics() } } } private func toggleTracking() { isTracking.toggle() if isTracking { // Notify phone that workout started connector.sendMessage([ "event": "workoutStarted", "timestamp": Date().timeIntervalSince1970 ]) } else { // Send final summary to phone do { try connector.updateApplicationContext([ "workoutComplete": true, "totalCalories": calories, "avgHeartRate": heartRate, "endTime": Date().timeIntervalSince1970 ]) } catch { print("Failed to update context: \(error)") } } } private func updateMetrics() { // Simulate heart rate (in real app, use HealthKit) heartRate = Double.random(in: 120...160) calories += Double.random(in: 0.1...0.3) // Send real-time updates if phone is reachable if connector.isReachable { connector.sendMessage([ "heartRate": heartRate, "calories": calories, "timestamp": Date().timeIntervalSince1970 ]) } } } ``` * Phone (Capacitor) ```typescript import { CapgoWatch } from '@capgo/capacitor-watch'; class WorkoutTracker { private heartRateData: number[] = []; private totalCalories = 0; async initialize() { // Listen for real-time workout updates await CapgoWatch.addListener('messageReceived', (event) => { const { heartRate, calories, timestamp } = event.message; if (heartRate) { this.heartRateData.push(heartRate); this.updateUI(heartRate, calories); } if (event.message.event === 'workoutStarted') { this.onWorkoutStarted(timestamp); } }); // Listen for workout completion via context await CapgoWatch.addListener('applicationContextReceived', (event) => { if (event.context.workoutComplete) { this.onWorkoutComplete(event.context); } }); } private onWorkoutStarted(timestamp: number) { console.log('Workout started at:', new Date(timestamp * 1000)); this.heartRateData = []; this.totalCalories = 0; } private onWorkoutComplete(data: any) { const avgHeartRate = data.avgHeartRate; const totalCalories = data.totalCalories; // Save to your backend this.saveWorkout({ avgHeartRate, totalCalories, endTime: data.endTime, heartRateHistory: this.heartRateData }); } private updateUI(heartRate: number, calories: number) { // Update your app's UI document.getElementById('heart-rate')!.textContent = `${Math.round(heartRate)} BPM`; document.getElementById('calories')!.textContent = `${Math.round(calories)} cal`; } private async saveWorkout(data: any) { // Save to your backend console.log('Saving workout:', data); } } const tracker = new WorkoutTracker(); tracker.initialize(); ``` ## Example 2: Smart Home Remote [Section titled “Example 2: Smart Home Remote”](#example-2-smart-home-remote) Control smart home devices from your watch. * Watch (SwiftUI) ```swift import SwiftUI import CapgoWatchSDK struct SmartHomeView: View { @ObservedObject var connector = WatchConnector.shared @State private var devices: [SmartDevice] = [] @State private var isLoading = false var body: some View { NavigationView { Group { if isLoading { ProgressView("Loading...") } else if devices.isEmpty { Text("No devices") .foregroundColor(.secondary) } else { List(devices) { device in DeviceRow(device: device, onToggle: { toggleDevice(device) }) } } } .navigationTitle("Home") .toolbar { Button(action: refreshDevices) { Image(systemName: "arrow.clockwise") } } } .onAppear { refreshDevices() } .onChange(of: connector.lastMessage) { message in handleMessage(message) } } private func refreshDevices() { guard connector.isReachable else { // Load from cached context loadFromContext() return } isLoading = true connector.sendMessage(["action": "getDevices"]) { reply in DispatchQueue.main.async { isLoading = false if let deviceList = reply["devices"] as? [[String: Any]] { devices = deviceList.compactMap { SmartDevice(from: $0) } } } } } private func toggleDevice(_ device: SmartDevice) { connector.sendMessage([ "action": "toggleDevice", "deviceId": device.id, "newState": !device.isOn ]) { reply in DispatchQueue.main.async { if reply["success"] as? Bool == true { // Update local state if let index = devices.firstIndex(where: { $0.id == device.id }) { devices[index].isOn.toggle() } } } } } private func loadFromContext() { if let deviceList = connector.applicationContext["devices"] as? [[String: Any]] { devices = deviceList.compactMap { SmartDevice(from: $0) } } } private func handleMessage(_ message: [String: Any]) { // Handle push updates from phone if let update = message["deviceUpdate"] as? [String: Any], let deviceId = update["id"] as? String, let isOn = update["isOn"] as? Bool { if let index = devices.firstIndex(where: { $0.id == deviceId }) { devices[index].isOn = isOn } } } } struct SmartDevice: Identifiable { let id: String let name: String let type: String var isOn: Bool init?(from dict: [String: Any]) { guard let id = dict["id"] as? String, let name = dict["name"] as? String, let type = dict["type"] as? String, let isOn = dict["isOn"] as? Bool else { return nil } self.id = id self.name = name self.type = type self.isOn = isOn } } struct DeviceRow: View { let device: SmartDevice let onToggle: () -> Void var body: some View { HStack { Image(systemName: iconName) .foregroundColor(device.isOn ? .yellow : .gray) Text(device.name) Spacer() Toggle("", isOn: .constant(device.isOn)) .labelsHidden() .onTapGesture { onToggle() } } } var iconName: String { switch device.type { case "light": return device.isOn ? "lightbulb.fill" : "lightbulb" case "thermostat": return "thermometer" case "lock": return device.isOn ? "lock.fill" : "lock.open" default: return "power" } } } ``` * Phone (Capacitor) ```typescript import { CapgoWatch } from '@capgo/capacitor-watch'; interface SmartDevice { id: string; name: string; type: string; isOn: boolean; } class SmartHomeController { private devices: SmartDevice[] = []; async initialize() { // Handle requests from watch await CapgoWatch.addListener('messageReceivedWithReply', async (event) => { const { action, deviceId, newState } = event.message; let response: any = { success: false }; switch (action) { case 'getDevices': response = { devices: this.devices }; break; case 'toggleDevice': const success = await this.toggleDevice(deviceId, newState); response = { success }; break; } await CapgoWatch.replyToMessage({ callbackId: event.callbackId, data: response }); }); // Load initial devices await this.loadDevices(); // Keep watch updated with device states await this.syncDevicesToWatch(); } private async loadDevices() { // Load from your smart home API this.devices = [ { id: '1', name: 'Living Room', type: 'light', isOn: true }, { id: '2', name: 'Bedroom', type: 'light', isOn: false }, { id: '3', name: 'Thermostat', type: 'thermostat', isOn: true }, { id: '4', name: 'Front Door', type: 'lock', isOn: true } ]; } private async toggleDevice(deviceId: string, newState: boolean): Promise<boolean> { try { // Call your smart home API const device = this.devices.find(d => d.id === deviceId); if (device) { device.isOn = newState; // Push update to watch const info = await CapgoWatch.getInfo(); if (info.isReachable) { await CapgoWatch.sendMessage({ data: { deviceUpdate: { id: deviceId, isOn: newState } } }); } return true; } return false; } catch (error) { console.error('Failed to toggle device:', error); return false; } } private async syncDevicesToWatch() { // Update application context for offline access await CapgoWatch.updateApplicationContext({ context: { devices: this.devices } }); } // Call this when devices change on the phone async onDeviceStateChanged(deviceId: string, isOn: boolean) { const device = this.devices.find(d => d.id === deviceId); if (device) { device.isOn = isOn; await this.syncDevicesToWatch(); } } } const controller = new SmartHomeController(); controller.initialize(); ``` ## Example 3: Notification Center [Section titled “Example 3: Notification Center”](#example-3-notification-center) Send custom notifications to the watch. * Phone (Capacitor) ```typescript import { CapgoWatch } from '@capgo/capacitor-watch'; class NotificationService { async sendNotification(title: string, body: string, data?: any) { const info = await CapgoWatch.getInfo(); if (info.isReachable) { // Send immediately if watch is reachable await CapgoWatch.sendMessage({ data: { type: 'notification', title, body, data, timestamp: Date.now() } }); } else { // Queue for later delivery await CapgoWatch.transferUserInfo({ userInfo: { type: 'notification', title, body, data, timestamp: Date.now() } }); } } async sendUrgentAlert(message: string) { // Use sendMessage for urgent alerts (requires watch to be reachable) const info = await CapgoWatch.getInfo(); if (!info.isReachable) { console.warn('Watch not reachable for urgent alert'); return false; } await CapgoWatch.sendMessage({ data: { type: 'urgentAlert', message, haptic: 'warning', timestamp: Date.now() } }); return true; } } // Usage const notifications = new NotificationService(); // Regular notification (queued if watch unavailable) await notifications.sendNotification( 'Order Update', 'Your order has shipped!', { orderId: '12345' } ); // Urgent alert (requires watch to be active) const sent = await notifications.sendUrgentAlert('Security alert: New login detected'); ``` * Watch (SwiftUI) ```swift import SwiftUI import WatchKit import CapgoWatchSDK struct NotificationView: View { @ObservedObject var connector = WatchConnector.shared @State private var notifications: [WatchNotification] = [] @State private var showAlert = false @State private var alertMessage = "" var body: some View { NavigationView { List(notifications) { notification in NotificationRow(notification: notification) } .navigationTitle("Notifications") } .onReceive(connector.$lastMessage) { message in handleMessage(message) } .alert("Alert", isPresented: $showAlert) { Button("OK") { } } message: { Text(alertMessage) } } private func handleMessage(_ message: [String: Any]) { guard let type = message["type"] as? String else { return } switch type { case "notification": let notification = WatchNotification( id: UUID().uuidString, title: message["title"] as? String ?? "", body: message["body"] as? String ?? "", timestamp: Date(timeIntervalSince1970: (message["timestamp"] as? Double ?? 0) / 1000) ) notifications.insert(notification, at: 0) // Play haptic WKInterfaceDevice.current().play(.notification) case "urgentAlert": alertMessage = message["message"] as? String ?? "Alert" showAlert = true // Play strong haptic for urgent alerts if let hapticType = message["haptic"] as? String { switch hapticType { case "warning": WKInterfaceDevice.current().play(.notification) DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { WKInterfaceDevice.current().play(.notification) } default: WKInterfaceDevice.current().play(.notification) } } default: break } } } struct WatchNotification: Identifiable { let id: String let title: String let body: String let timestamp: Date } struct NotificationRow: View { let notification: WatchNotification var body: some View { VStack(alignment: .leading, spacing: 4) { Text(notification.title) .font(.headline) Text(notification.body) .font(.caption) .foregroundColor(.secondary) Text(notification.timestamp, style: .relative) .font(.caption2) .foregroundColor(.secondary) } .padding(.vertical, 4) } } ``` ## Example 4: Data Sync Service [Section titled “Example 4: Data Sync Service”](#example-4-data-sync-service) Keep data synchronized between phone and watch. ```typescript import { CapgoWatch } from '@capgo/capacitor-watch'; class DataSyncService { private syncQueue: any[] = []; private isSyncing = false; async initialize() { // Listen for sync requests from watch await CapgoWatch.addListener('messageReceivedWithReply', async (event) => { if (event.message.action === 'sync') { const data = await this.getDataForSync(event.message.lastSyncTime); await CapgoWatch.replyToMessage({ callbackId: event.callbackId, data: { items: data, syncTime: Date.now() } }); } }); // Listen for data from watch await CapgoWatch.addListener('userInfoReceived', (event) => { this.handleWatchData(event.userInfo); }); // Monitor connectivity for sync opportunities await CapgoWatch.addListener('reachabilityChanged', (event) => { if (event.isReachable && this.syncQueue.length > 0) { this.processSyncQueue(); } }); } // Push important data to watch (guaranteed delivery) async pushToWatch(data: any) { await CapgoWatch.transferUserInfo({ userInfo: { type: 'dataUpdate', data, timestamp: Date.now() } }); } // Update shared state (latest value only) async updateSharedState(state: any) { await CapgoWatch.updateApplicationContext({ context: { ...state, lastUpdated: Date.now() } }); } // Queue data for sync when watch becomes available queueForSync(data: any) { this.syncQueue.push(data); this.attemptSync(); } private async attemptSync() { const info = await CapgoWatch.getInfo(); if (info.isReachable) { await this.processSyncQueue(); } } private async processSyncQueue() { if (this.isSyncing || this.syncQueue.length === 0) return; this.isSyncing = true; while (this.syncQueue.length > 0) { const item = this.syncQueue.shift(); await CapgoWatch.transferUserInfo({ userInfo: item }); } this.isSyncing = false; } private async getDataForSync(lastSyncTime: number): Promise<any[]> { // Return data modified since lastSyncTime // This would query your database/API return []; } private handleWatchData(data: any) { console.log('Received from watch:', data); // Process and save data from watch } } ``` ## Best Practices [Section titled “Best Practices”](#best-practices) ### 1. Choose the Right Transfer Method [Section titled “1. Choose the Right Transfer Method”](#1-choose-the-right-transfer-method) | Method | Use Case | Delivery | | -------------------------- | --------------------------- | -------------------------------- | | `sendMessage` | Interactive, time-sensitive | Immediate (fails if unreachable) | | `updateApplicationContext` | Current app state | Latest value only | | `transferUserInfo` | Important data | Queued, guaranteed | ### 2. Handle Offline Gracefully [Section titled “2. Handle Offline Gracefully”](#2-handle-offline-gracefully) ```typescript async function smartSend(data: any, important: boolean) { const info = await CapgoWatch.getInfo(); if (info.isReachable) { // Send immediately await CapgoWatch.sendMessage({ data }); } else if (important) { // Queue for later await CapgoWatch.transferUserInfo({ userInfo: data }); } else { // Update context (will be available when watch opens app) await CapgoWatch.updateApplicationContext({ context: data }); } } ``` ### 3. Minimize Data Size [Section titled “3. Minimize Data Size”](#3-minimize-data-size) ```swift // Bad - sending large objects connector.sendMessage(["user": fullUserObject]) // Good - send only what's needed connector.sendMessage([ "userId": user.id, "name": user.displayName, "avatarUrl": user.avatarUrl ]) ``` ### 4. Use Haptics Appropriately [Section titled “4. Use Haptics Appropriately”](#4-use-haptics-appropriately) ```swift import WatchKit // Success feedback WKInterfaceDevice.current().play(.success) // Failure feedback WKInterfaceDevice.current().play(.failure) // Navigation feedback WKInterfaceDevice.current().play(.click) // Notification WKInterfaceDevice.current().play(.notification) ``` ### 5. Cache on Watch [Section titled “5. Cache on Watch”](#5-cache-on-watch) ```swift class DataCache { private let defaults = UserDefaults.standard func save(_ data: [String: Any], forKey key: String) { if let encoded = try? JSONSerialization.data(withJSONObject: data) { defaults.set(encoded, forKey: key) } } func load(forKey key: String) -> [String: Any]? { guard let data = defaults.data(forKey: key), let dict = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { return nil } return dict } } ``` ## Next Steps [Section titled “Next Steps”](#next-steps) * [Watch App Setup](/docs/plugins/watch/watch-app-setup/) - Create your first watch app * [API Reference](/docs/plugins/watch/getting-started/#api-reference) - Complete API documentation * [GitHub Repository](https://github.com/Cap-go/capacitor-watch) - Source code and issues # Getting Started > Learn how to install and configure the Capacitor Watch plugin for bidirectional communication between iPhone and Apple Watch. 1. **Install the package** ```sh bun add @capgo/capacitor-watch ``` 2. **Sync with native projects** ```sh bunx cap sync ``` 3. **Configure the plugin** **Basic Usage Example:** ```typescript import { CapgoWatch } from '@capgo/capacitor-watch'; // Check watch connectivity status const info = await CapgoWatch.getInfo(); console.log('Watch paired:', info.isPaired); console.log('Watch reachable:', info.isReachable); // Listen for messages from watch await CapgoWatch.addListener('messageReceived', (event) => { console.log('Message from watch:', event.message); }); ``` **Send a Message to Watch:** ```typescript // Check if watch is reachable first const info = await CapgoWatch.getInfo(); if (info.isReachable) { await CapgoWatch.sendMessage({ data: { action: 'refresh', timestamp: Date.now() } }); } ``` * iOS **Required iOS Setup:** 1. Add the WatchConnectivity capability to your iOS app in Xcode 2. Create a watchOS app target in your Xcode project 3. Implement WatchConnectivity in your watchOS app (see Watch App Implementation below) The plugin automatically activates the WCSession when the plugin loads. * Android Apple Watch is only supported on iOS. On Android, all methods will reject with “Apple Watch is only supported on iOS” error. The `getInfo()` method returns `isSupported: false`. 4. **Handle messages that require a reply** ```typescript // Listen for messages that need a response await CapgoWatch.addListener('messageReceivedWithReply', async (event) => { console.log('Request from watch:', event.message); // Process the request const result = await processWatchRequest(event.message); // Send reply back to watch await CapgoWatch.replyToMessage({ callbackId: event.callbackId, data: { result } }); }); ``` 5. **Sync application state** ```typescript // Update application context (latest value only) await CapgoWatch.updateApplicationContext({ context: { theme: 'dark', userId: '123', lastSync: Date.now() } }); // Listen for context updates from watch await CapgoWatch.addListener('applicationContextReceived', (event) => { console.log('Context from watch:', event.context); }); ``` 6. **Transfer user info reliably** ```typescript // Queue data for reliable delivery (even when watch is offline) await CapgoWatch.transferUserInfo({ userInfo: { recordId: '456', action: 'created', data: { name: 'Item 1' } } }); // Listen for user info transfers await CapgoWatch.addListener('userInfoReceived', (event) => { console.log('User info from watch:', event.userInfo); }); ``` 7. **Monitor connectivity** ```typescript // Track reachability changes await CapgoWatch.addListener('reachabilityChanged', (event) => { console.log('Watch reachable:', event.isReachable); if (event.isReachable) { // Watch is now available for interactive messaging } }); // Track session activation state await CapgoWatch.addListener('activationStateChanged', (event) => { // 0 = notActivated, 1 = inactive, 2 = activated console.log('Session state:', event.state); }); ``` ## Watch App Implementation [Section titled “Watch App Implementation”](#watch-app-implementation) Your watchOS app needs to implement WatchConnectivity. Here’s a SwiftUI example: ```swift import SwiftUI import WatchConnectivity @main struct MyWatchApp: App { init() { WatchViewModel.shared.activate() } var body: some Scene { WindowGroup { ContentView() } } } class WatchViewModel: NSObject, ObservableObject, WCSessionDelegate { static let shared = WatchViewModel() @Published var lastMessage: [String: Any] = [:] func activate() { guard WCSession.isSupported() else { return } WCSession.default.delegate = self WCSession.default.activate() } // Send message to iPhone func sendToPhone(_ data: [String: Any]) { guard WCSession.default.isReachable else { print("iPhone not reachable") return } WCSession.default.sendMessage(data, replyHandler: nil) } // Send message with reply func sendToPhoneWithReply(_ data: [String: Any], completion: @escaping ([String: Any]) -> Void) { guard WCSession.default.isReachable else { return } WCSession.default.sendMessage(data, replyHandler: completion) } // Receive message from iPhone func session(_ session: WCSession, didReceiveMessage message: [String: Any]) { DispatchQueue.main.async { self.lastMessage = message } } // Receive application context func session(_ session: WCSession, didReceiveApplicationContext applicationContext: [String: Any]) { DispatchQueue.main.async { self.lastMessage = applicationContext } } // Required delegate methods func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) { print("Watch session activated: \(activationState.rawValue)") } } ``` ## API Reference [Section titled “API Reference”](#api-reference) ### Methods [Section titled “Methods”](#methods) #### `sendMessage(options: SendMessageOptions)` [Section titled “sendMessage(options: SendMessageOptions)”](#sendmessageoptions-sendmessageoptions) Send an interactive message to the watch. Requires watch to be reachable. **Parameters:** * `data`: Object - The data to send to the watch #### `updateApplicationContext(options: UpdateContextOptions)` [Section titled “updateApplicationContext(options: UpdateContextOptions)”](#updateapplicationcontextoptions-updatecontextoptions) Update application context. Only latest value is kept. **Parameters:** * `context`: Object - The context data to sync #### `transferUserInfo(options: TransferUserInfoOptions)` [Section titled “transferUserInfo(options: TransferUserInfoOptions)”](#transferuserinfooptions-transferuserinfooptions) Queue user info for reliable delivery. **Parameters:** * `userInfo`: Object - The user info to transfer #### `replyToMessage(options: ReplyMessageOptions)` [Section titled “replyToMessage(options: ReplyMessageOptions)”](#replytomessageoptions-replymessageoptions) Reply to a message that requested a response. **Parameters:** * `callbackId`: string - The callback ID from messageReceivedWithReply event * `data`: Object - The reply data #### `getInfo()` [Section titled “getInfo()”](#getinfo) Get watch connectivity status. **Returns:** `WatchInfo` object with: * `isSupported`: boolean - Whether WatchConnectivity is available * `isPaired`: boolean - Whether a watch is paired * `isWatchAppInstalled`: boolean - Whether watch app is installed * `isReachable`: boolean - Whether watch is reachable * `activationState`: number - Session state (0/1/2) #### `getPluginVersion()` [Section titled “getPluginVersion()”](#getpluginversion) Get the native plugin version. ### Events [Section titled “Events”](#events) | Event | Description | | ---------------------------- | ----------------------------------------------- | | `messageReceived` | Simple message from watch | | `messageReceivedWithReply` | Message expecting a reply (includes callbackId) | | `applicationContextReceived` | Context update from watch | | `userInfoReceived` | User info transfer from watch | | `reachabilityChanged` | Watch connectivity changed | | `activationStateChanged` | Session activation state changed | ## Communication Patterns [Section titled “Communication Patterns”](#communication-patterns) ### Immediate Messaging (`sendMessage`) [Section titled “Immediate Messaging (sendMessage)”](#immediate-messaging-sendmessage) * Requires watch to be reachable * Best for interactive, time-sensitive communication * Fails immediately if watch is not available ### Application Context (`updateApplicationContext`) [Section titled “Application Context (updateApplicationContext)”](#application-context-updateapplicationcontext) * Latest value only - previous values are overwritten * Best for syncing current app state * Delivered when watch becomes available ### User Info Transfer (`transferUserInfo`) [Section titled “User Info Transfer (transferUserInfo)”](#user-info-transfer-transferuserinfo) * Queued and delivered in order * Best for important data that must be delivered * Works even when watch is temporarily unreachable ## Platform Notes [Section titled “Platform Notes”](#platform-notes) ### iOS [Section titled “iOS”](#ios) * Requires iOS 15.0 or later * Uses WatchConnectivity framework * Session automatically activates on plugin load * Supports background delivery for context and user info ### Android [Section titled “Android”](#android) * Not supported (Apple Watch is iOS-only) * All methods reject with appropriate error * `getInfo()` returns `isSupported: false` ### Web [Section titled “Web”](#web) * Not supported * All methods reject with unavailable error * `getInfo()` returns `isSupported: false` ## Common Use Cases [Section titled “Common Use Cases”](#common-use-cases) 1. **Data Sync**: Keep watch and phone data in sync 2. **Remote Control**: Control phone features from watch 3. **Notifications**: Send custom notifications to watch 4. **Health Data**: Share fitness and health metrics 5. **Media Control**: Control music playback from watch 6. **Smart Home**: Control devices from your wrist ## Troubleshooting [Section titled “Troubleshooting”](#troubleshooting) **Watch not reachable:** * Ensure watch is within Bluetooth range * Check that both apps are running * Verify WCSession is activated on both sides **Messages not received:** * Check that listeners are registered before sending * Verify the watch app implements WCSessionDelegate * Use `transferUserInfo` for guaranteed delivery **Session not activating:** * Ensure WatchConnectivity capability is added in Xcode * Check that watch app has the companion bundle ID * Verify both apps target compatible OS versions # Creating a watchOS App > Complete step-by-step guide to creating an Apple Watch app for your Capacitor iOS project with bidirectional communication. This guide walks you through creating a watchOS companion app from scratch, including project setup in Xcode, integrating the CapgoWatchSDK, and building a functional watch app with SwiftUI. ## Prerequisites [Section titled “Prerequisites”](#prerequisites) Before you begin, ensure you have: * **Xcode 15 or later** (download from Mac App Store) * **macOS Sonoma or later** (for latest watchOS SDK) * **An existing Capacitor iOS project** (run `npx cap add ios` if you haven’t) * **Apple Developer account** (free account works for development) ## Project Structure Overview [Section titled “Project Structure Overview”](#project-structure-overview) After completing this guide, your project will have this structure: * ios/ * App/ * App/ (your main iOS app) * … * App.xcodeproj * App.xcworkspace (use this to open the project) * Podfile * MyWatch/ (new watch app) * MyWatch/ (watch app source) * MyWatchApp.swift * ContentView\.swift * Assets.xcassets/ * … * MyWatch.xcodeproj ## Step 1: Open Your iOS Project in Xcode [Section titled “Step 1: Open Your iOS Project in Xcode”](#step-1-open-your-ios-project-in-xcode) 1. Navigate to your Capacitor project’s `ios/App` folder 2. Open `App.xcworkspace` (not `.xcodeproj`) by double-clicking it 3. Wait for Xcode to index the project Caution Always open the `.xcworkspace` file, not `.xcodeproj`. The workspace includes CocoaPods dependencies that your project needs. ## Step 2: Add a watchOS Target [Section titled “Step 2: Add a watchOS Target”](#step-2-add-a-watchos-target) 1. In Xcode, go to **File → New → Target…** 2. In the template chooser: * Select **watchOS** tab at the top * Choose **App** * Click **Next** 3. Configure your watch app: * **Product Name**: `MyWatch` (or your preferred name) * **Team**: Select your Apple Developer team * **Organization Identifier**: Should match your iOS app (e.g., `app.capgo`) * **Bundle Identifier**: Will be auto-generated (e.g., `app.capgo.myapp.watchkitapp`) * **Language**: Swift * **User Interface**: SwiftUI * **Watch App Type**: App (not App for Existing iOS App) * Uncheck **Include Notification Scene** (unless you need it) * Uncheck **Include Complication** (unless you need it) 4. Click **Finish** 5. When prompted “Activate ‘MyWatch’ scheme?”, click **Activate** ## Step 3: Configure Watch App Settings [Section titled “Step 3: Configure Watch App Settings”](#step-3-configure-watch-app-settings) 1. In the Project Navigator (left sidebar), select your project (the blue icon at the top) 2. Select your watch target (e.g., “MyWatch”) from the targets list 3. Go to the **General** tab: * **Display Name**: The name shown under the app icon (e.g., “My App”) * **Bundle Identifier**: Should end with `.watchkitapp` * **Version**: Match your iOS app version * **Build**: Match your iOS app build number 4. Go to **Signing & Capabilities** tab: * Enable **Automatically manage signing** * Select your **Team** * Xcode will create provisioning profiles automatically 5. Set **Deployment Info**: * **Minimum Deployments**: watchOS 9.0 or later ## Step 4: Add CapgoWatchSDK via Swift Package Manager [Section titled “Step 4: Add CapgoWatchSDK via Swift Package Manager”](#step-4-add-capgowatchsdk-via-swift-package-manager) The CapgoWatchSDK provides a ready-to-use `WatchConnector` class for communication. 1. In Xcode, go to **File → Add Package Dependencies…** 2. In the search field, enter: ```plaintext https://github.com/Cap-go/capacitor-watch.git ``` 3. Press Enter and wait for Xcode to fetch the package 4. Configure the package: * **Dependency Rule**: “Up to Next Major Version” with “8.0.0” * Click **Add Package** 5. Choose which products to add: * **IMPORTANT**: Only select `CapgoWatchSDK` * Make sure it’s added to your **watch target** (e.g., “MyWatch”), not the iOS app * Click **Add Package** Tip The `CapgoWatchSDK` is specifically designed for watchOS apps. It provides `WatchConnector`, an ObservableObject that handles all WatchConnectivity complexities for you. ## Step 5: Implement the Watch App [Section titled “Step 5: Implement the Watch App”](#step-5-implement-the-watch-app) Now let’s create the watch app code. Replace the auto-generated files with the following: ### 5.1 Create the App Entry Point [Section titled “5.1 Create the App Entry Point”](#51-create-the-app-entry-point) Edit `MyWatch/MyWatchApp.swift`: ```swift import SwiftUI import CapgoWatchSDK @main struct MyWatchApp: App { init() { // Activate WatchConnectivity when app launches WatchConnector.shared.activate() } var body: some Scene { WindowGroup { ContentView() } } } ``` ### 5.2 Create the Main View [Section titled “5.2 Create the Main View”](#52-create-the-main-view) Edit `MyWatch/ContentView.swift`: ```swift import SwiftUI import CapgoWatchSDK struct ContentView: View { // Observe the WatchConnector for automatic UI updates @ObservedObject var connector = WatchConnector.shared // Local state @State private var messageText = "" @State private var statusMessage = "Ready" var body: some View { ScrollView { VStack(spacing: 16) { // Connection Status ConnectionStatusView(connector: connector) Divider() // Message Input TextField("Message", text: $messageText) .textFieldStyle(.roundedBorder) // Send Buttons HStack { Button("Send") { sendMessage() } .disabled(!connector.isReachable || messageText.isEmpty) Button("Request") { sendWithReply() } .disabled(!connector.isReachable || messageText.isEmpty) } Divider() // Status Text(statusMessage) .font(.caption) .foregroundColor(.secondary) // Last Received Message if !connector.lastMessage.isEmpty { VStack(alignment: .leading) { Text("Last Message:") .font(.caption) .foregroundColor(.secondary) Text(formatMessage(connector.lastMessage)) .font(.caption2) } .frame(maxWidth: .infinity, alignment: .leading) } } .padding() } } private func sendMessage() { connector.sendMessage(["text": messageText, "timestamp": Date().timeIntervalSince1970]) statusMessage = "Message sent" messageText = "" } private func sendWithReply() { connector.sendMessage(["text": messageText, "needsReply": true]) { reply in DispatchQueue.main.async { statusMessage = "Reply: \(formatMessage(reply))" } } messageText = "" } private func formatMessage(_ message: [String: Any]) -> String { message.map { "\($0.key): \($0.value)" }.joined(separator: ", ") } } // Separate view for connection status struct ConnectionStatusView: View { @ObservedObject var connector: WatchConnector var body: some View { HStack { Circle() .fill(connector.isReachable ? Color.green : Color.red) .frame(width: 12, height: 12) Text(connector.isReachable ? "Connected" : "Disconnected") .font(.headline) Spacer() if connector.isActivated { Image(systemName: "checkmark.circle.fill") .foregroundColor(.green) } } } } #Preview { ContentView() } ``` ## Step 6: Configure iOS App for WatchConnectivity [Section titled “Step 6: Configure iOS App for WatchConnectivity”](#step-6-configure-ios-app-for-watchconnectivity) Your iOS app also needs WatchConnectivity capability. 1. In the Project Navigator, select your project 2. Select your **iOS App target** (not the watch target) 3. Go to **Signing & Capabilities** tab 4. Click **+ Capability** 5. Search for and add **WatchConnectivity** (if available) or it may be added automatically 6. The Capacitor plugin handles the iOS side automatically, but ensure your Info.plist has: ```xml <key>WKCompanionAppBundleIdentifier</key> <string>app.capgo.myapp.watchkitapp</string> ``` ## Step 7: Build and Run [Section titled “Step 7: Build and Run”](#step-7-build-and-run) ### Run on Simulator [Section titled “Run on Simulator”](#run-on-simulator) 1. Select your watch scheme from the scheme selector (top of Xcode window) 2. Choose a watch simulator: * Click on the device selector next to the scheme * Select an Apple Watch simulator (e.g., “Apple Watch Series 9 (45mm)”) 3. Click the **Run** button (▶️) or press `Cmd + R` 4. The iOS Simulator will launch with both iPhone and Apple Watch ### Run on Physical Device [Section titled “Run on Physical Device”](#run-on-physical-device) 1. Connect your iPhone via USB 2. Ensure your Apple Watch is paired with that iPhone 3. Select your watch scheme 4. Select your physical Apple Watch from the device list 5. Click **Run** 6. First time: You may need to trust your computer on both devices Tip To debug both apps simultaneously: 1. Run the iOS app first 2. Then run the watch app with “Debug → Attach to Process” for the watch ## Step 8: Test Communication [Section titled “Step 8: Test Communication”](#step-8-test-communication) ### From iPhone (Capacitor) to Watch [Section titled “From iPhone (Capacitor) to Watch”](#from-iphone-capacitor-to-watch) In your Capacitor app: ```typescript import { CapgoWatch } from '@capgo/capacitor-watch'; // Check connection const info = await CapgoWatch.getInfo(); console.log('Watch reachable:', info.isReachable); // Send a message if (info.isReachable) { await CapgoWatch.sendMessage({ data: { action: 'update', value: 'Hello from iPhone!' } }); } ``` ### From Watch to iPhone [Section titled “From Watch to iPhone”](#from-watch-to-iphone) The watch app uses `WatchConnector`: ```swift // Send message (fire and forget) WatchConnector.shared.sendMessage(["action": "buttonTapped"]) // Send message with reply WatchConnector.shared.sendMessage(["request": "getData"]) { reply in print("Got reply: \(reply)") } ``` ### Handle Messages on iPhone [Section titled “Handle Messages on iPhone”](#handle-messages-on-iphone) ```typescript // Listen for messages from watch await CapgoWatch.addListener('messageReceived', (event) => { console.log('Message from watch:', event.message); // { action: 'buttonTapped' } }); // Handle messages that need a reply await CapgoWatch.addListener('messageReceivedWithReply', async (event) => { console.log('Request from watch:', event.message); // Send reply back await CapgoWatch.replyToMessage({ callbackId: event.callbackId, data: { status: 'success', items: ['item1', 'item2'] } }); }); ``` ## Advanced: Custom Delegate for More Control [Section titled “Advanced: Custom Delegate for More Control”](#advanced-custom-delegate-for-more-control) If you need more control, implement `WatchConnectorDelegate`: ```swift import SwiftUI import CapgoWatchSDK class WatchHandler: WatchConnectorDelegate { func didReceiveMessage(_ message: [String: Any]) { print("Received: \(message)") // Handle incoming message } func didReceiveMessageWithReply(_ message: [String: Any], replyHandler: @escaping ([String: Any]) -> Void) { print("Received request: \(message)") // Process and send reply replyHandler(["status": "processed"]) } func didReceiveApplicationContext(_ context: [String: Any]) { print("Context updated: \(context)") } func didReceiveUserInfo(_ userInfo: [String: Any]) { print("User info received: \(userInfo)") } func reachabilityDidChange(_ isReachable: Bool) { print("Reachability changed: \(isReachable)") } func activationDidComplete(with state: WCSessionActivationState) { print("Activation completed: \(state.rawValue)") } } // In your app setup: let handler = WatchHandler() WatchConnector.shared.delegate = handler WatchConnector.shared.activate() ``` ## Troubleshooting [Section titled “Troubleshooting”](#troubleshooting) ### Watch App Not Appearing on Watch [Section titled “Watch App Not Appearing on Watch”](#watch-app-not-appearing-on-watch) 1. Ensure bundle IDs are correctly related (watch app bundle ID should be iOS app bundle ID + `.watchkitapp`) 2. Check that both apps are signed with the same team 3. On physical device: Open Watch app on iPhone → My Watch → scroll to find your app → toggle ON ### Messages Not Being Received [Section titled “Messages Not Being Received”](#messages-not-being-received) 1. Verify both apps have WCSession activated 2. Check `isReachable` before sending messages 3. For guaranteed delivery, use `transferUserInfo` instead of `sendMessage` 4. Ensure listeners are registered before the other device sends messages ### ”Session Not Activated” Error [Section titled “”Session Not Activated” Error”](#session-not-activated-error) 1. Call `WatchConnector.shared.activate()` early in app lifecycle 2. On iOS, the plugin activates automatically - ensure plugin is imported 3. Check that WatchConnectivity capability is added to iOS target ### Build Errors with CapgoWatchSDK [Section titled “Build Errors with CapgoWatchSDK”](#build-errors-with-capgowatchsdk) 1. Ensure the package is added to the **watch target**, not iOS target 2. Clean build folder: **Product → Clean Build Folder** (Cmd + Shift + K) 3. Reset package caches: **File → Packages → Reset Package Caches** ### Simulator Issues [Section titled “Simulator Issues”](#simulator-issues) 1. Reset the simulators: **Device → Erase All Content and Settings** 2. Ensure iOS and watchOS simulators are compatible pairs 3. Both simulators need to be running for communication to work ## Next Steps [Section titled “Next Steps”](#next-steps) * [API Reference](/docs/plugins/watch/getting-started/#api-reference) - Complete API documentation * [Communication Patterns](/docs/plugins/watch/getting-started/#communication-patterns) - When to use each method * [Example App](https://github.com/Cap-go/capacitor-watch/tree/main/example-app) - Full working example # @capgo/capacitor-webview-crash > Detect recovered WebView crashes and handle lost in-memory state after the WebView restarts. ## Overview [Section titled “Overview”](#overview) This plugin stores a native crash marker when the previous Capacitor WebView process dies, then exposes that marker to the next JavaScript runtime after the app recovers. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `getPendingCrashInfo` - Returns the stored native crash marker, or `null` when nothing is pending. * `clearPendingCrashInfo` - Clears the stored crash marker after your app has restored its state. * `simulateCrashRecovery` - Creates a fake crash marker so recovery flows can be tested locally. * `addListener` - Fires `webViewRestoredAfterCrash` when a listener attaches and a crash marker is still pending. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ----------------------- | ----------------------------------------------------------------------------------------------- | | `getPendingCrashInfo` | Returns the stored native crash marker, or `null` when nothing is pending. | | `clearPendingCrashInfo` | Clears the stored crash marker after your app has restored its state. | | `simulateCrashRecovery` | Creates a fake crash marker so recovery flows can be tested locally. | | `addListener` | Fires `webViewRestoredAfterCrash` when a listener attaches and a crash marker is still pending. | | `removeAllListeners` | Removes all plugin listeners. | ## Notes [Section titled “Notes”](#notes) * This plugin detects recovery after a WebView crash. It does not prevent the underlying crash. * The recovered JavaScript runtime is new, so any in-memory state from the previous WebView is already gone when this API fires. * On Android, extra fields such as `didCrash` and `rendererPriorityAtExit` may be available. * On iOS, the plugin records `appState` when the terminated WebView process is observed. ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-webview-crash](https://github.com/Cap-go/capacitor-webview-crash/). # Getting Started > Install @capgo/capacitor-webview-crash and handle recovered WebView crashes in your Capacitor app startup flow. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-webview-crash bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { WebViewCrash } from '@capgo/capacitor-webview-crash'; ``` ## Recommended recovery flow [Section titled “Recommended recovery flow”](#recommended-recovery-flow) Attach the listener as early as possible in your app startup so the recovered runtime can react before users continue navigating: ```typescript import { WebViewCrash } from '@capgo/capacitor-webview-crash'; await WebViewCrash.addListener('webViewRestoredAfterCrash', async (info) => { console.log('Recovered after a WebView crash', info); // Rehydrate critical state, reopen the correct screen, or prompt the user to retry. await WebViewCrash.clearPendingCrashInfo(); }); const pending = await WebViewCrash.getPendingCrashInfo(); // Note: the listener callback may have already cleared the pending marker. if (pending.value) { console.log('Pending crash marker', pending.value); } ``` ## API overview [Section titled “API overview”](#api-overview) ### `getPendingCrashInfo` [Section titled “getPendingCrashInfo”](#getpendingcrashinfo) Returns the stored native crash marker, or `null` when nothing is pending. ```typescript const pending = await WebViewCrash.getPendingCrashInfo(); if (pending.value) { console.log(pending.value.platform, pending.value.reason); } ``` ### `clearPendingCrashInfo` [Section titled “clearPendingCrashInfo”](#clearpendingcrashinfo) Clears the stored crash marker after your recovery handling is finished. ```typescript await WebViewCrash.clearPendingCrashInfo(); ``` ### `simulateCrashRecovery` [Section titled “simulateCrashRecovery”](#simulatecrashrecovery) Creates a fake crash marker so QA and local debugging can exercise the recovery path without crashing a real WebView. ```typescript const simulated = await WebViewCrash.simulateCrashRecovery(); console.log(simulated.value); ``` ## Platform notes [Section titled “Platform notes”](#platform-notes) * Android stores crash metadata from `onRenderProcessGone`, including `didCrash` and `rendererPriorityAtExit` when the platform provides them. * iOS stores crash metadata from `webViewWebContentProcessDidTerminate` and adds the current application state when available. * Web does not detect real renderer crashes. The web implementation only simulates the behavior with local storage. ## Type reference [Section titled “Type reference”](#type-reference) ### `PendingCrashInfoResult` [Section titled “PendingCrashInfoResult”](#pendingcrashinforesult) ```typescript export interface PendingCrashInfoResult { /** * Stored crash metadata, or `null` when no marker is pending. */ value: WebViewCrashInfo | null; } ``` ### `WebViewCrashInfo` [Section titled “WebViewCrashInfo”](#webviewcrashinfo) ```typescript export interface WebViewCrashInfo { /** * Platform that detected and stored the crash marker. */ platform: WebViewCrashPlatform; /** * Unix timestamp in milliseconds for when the crash marker was written. */ timestamp: number; /** * ISO-8601 version of `timestamp`. */ timestampISO: string; /** * Platform-specific reason for the crash marker. */ reason: WebViewCrashReason; /** * Last known WebView URL when the crash marker was written. */ url?: string; /** * Android-only hint from `RenderProcessGoneDetail.didCrash()`. */ didCrash?: boolean; /** * Android-only renderer priority reported at exit. */ rendererPriorityAtExit?: number; /** * iOS-only application state captured when the WebView process died. */ appState?: WebViewCrashAppState; } ``` ### `WebViewCrashPlatform` [Section titled “WebViewCrashPlatform”](#webviewcrashplatform) ```typescript export type WebViewCrashPlatform = 'android' | 'ios' | 'web'; ``` ### `WebViewCrashReason` [Section titled “WebViewCrashReason”](#webviewcrashreason) ```typescript export type WebViewCrashReason = 'renderProcessGone' | 'webContentProcessDidTerminate' | 'simulated'; ``` ### `WebViewCrashAppState` [Section titled “WebViewCrashAppState”](#webviewcrashappstate) ```typescript export type WebViewCrashAppState = 'active' | 'inactive' | 'background' | 'unknown'; ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-webview-guardian > Capacitor plugin to Detect when the WebView was killed in the background and relaunch it on foreground. ## Overview [Section titled “Overview”](#overview) Capacitor plugin to Detect when the WebView was killed in the background and relaunch it on foreground. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `startMonitoring` - Starts observing foreground events and automatically checks the WebView health. * `stopMonitoring` - Stops any automatic foreground monitoring. * `getState` - Returns the latest known monitoring state. * `checkNow` - Forces a WebView health probe immediately. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ----------------- | ------------------------------------------------------------------------------- | | `startMonitoring` | Starts observing foreground events and automatically checks the WebView health. | | `stopMonitoring` | Stops any automatic foreground monitoring. | | `getState` | Returns the latest known monitoring state. | | `checkNow` | Forces a WebView health probe immediately. | | `addListener` | See the source definitions for current behavior. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-webview-guardian](https://github.com/Cap-go/capacitor-webview-guardian/). # Getting Started > Install @capgo/capacitor-webview-guardian and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-webview-guardian bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { WebviewGuardian } from '@capgo/capacitor-webview-guardian'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `startMonitoring` [Section titled “startMonitoring”](#startmonitoring) Starts observing foreground events and automatically checks the WebView health. ```typescript import { WebviewGuardian } from '@capgo/capacitor-webview-guardian'; await WebviewGuardian.startMonitoring(); ``` ### `stopMonitoring` [Section titled “stopMonitoring”](#stopmonitoring) Stops any automatic foreground monitoring. ```typescript import { WebviewGuardian } from '@capgo/capacitor-webview-guardian'; await WebviewGuardian.stopMonitoring(); ``` ### `getState` [Section titled “getState”](#getstate) Returns the latest known monitoring state. ```typescript import { WebviewGuardian } from '@capgo/capacitor-webview-guardian'; await WebviewGuardian.getState(); ``` ### `checkNow` [Section titled “checkNow”](#checknow) Forces a WebView health probe immediately. ```typescript import { WebviewGuardian } from '@capgo/capacitor-webview-guardian'; await WebviewGuardian.checkNow(); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `StartMonitoringOptions` [Section titled “StartMonitoringOptions”](#startmonitoringoptions) ```typescript export interface StartMonitoringOptions { /** * Delay (in ms) before running a health check after the app re-enters the foreground. * Defaults to 600ms to let the bridge finish resuming. */ foregroundDebounceMs?: number; /** * Script executed via `evaluateJavascript`/`evaluateJavaScript` to confirm the WebView is alive. * Defaults to `document.readyState`. */ pingScript?: string; /** * Automatically reloads the WebView when a terminated render process is detected. * Disable to receive `webviewCrashed` events and restart manually. */ autoRestart?: boolean; /** * Strategy used when restarting the WebView. Defaults to `reload`. */ restartStrategy?: RestartStrategy; /** * Custom HTTPS/HTTP URL to load when `restartStrategy` is `customUrl`. */ customRestartUrl?: string; /** * Emits verbose logging in the native layer when true. */ debug?: boolean; /** * Whether an immediate health check should be executed right after enabling monitoring. * Defaults to `true`. */ runInitialCheck?: boolean; } ``` ### `GuardianState` [Section titled “GuardianState”](#guardianstate) ```typescript export interface GuardianState { monitoring: boolean; reason: string; timestamp: string; lastHealthyAt?: string; lastRestartAt?: string; lastCrashAt?: string; pendingRestartReason?: string; error?: string; } ``` ### `CheckNowOptions` [Section titled “CheckNowOptions”](#checknowoptions) ```typescript export interface CheckNowOptions { /** * Text tag describing why a manual check is being requested. */ reason?: string; } ``` ### `CheckResult` [Section titled “CheckResult”](#checkresult) ```typescript export interface CheckResult { healthy: boolean; restarted: boolean; reason: string; timestamp: string; error?: string; pendingRestart?: boolean; } ``` ### `GuardianEvent` [Section titled “GuardianEvent”](#guardianevent) ```typescript export type GuardianEvent = GuardianState; ``` ### `RestartStrategy` [Section titled “RestartStrategy”](#restartstrategy) ```typescript export type RestartStrategy = 'reload' | 'reloadFromOrigin' | 'customUrl'; ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-webview-version-checker > Public API for checking WebView freshness and guiding users to updates. ## Overview [Section titled “Overview”](#overview) Public API for checking WebView freshness and guiding users to updates. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `check` - Runs a version check and returns the latest known status. * `startMonitoring` - Enables background monitoring (typically on app resume). * `stopMonitoring` - Disables monitoring. * `getLastStatus` - Returns the last resolved status, or `null` if no check was run yet. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------ | -------------------------------------------------------------------- | | `check` | Runs a version check and returns the latest known status. | | `startMonitoring` | Enables background monitoring (typically on app resume). | | `stopMonitoring` | Disables monitoring. | | `getLastStatus` | Returns the last resolved status, or `null` if no check was run yet. | | `showUpdatePrompt` | Shows a native prompt asking the user to update the WebView. | | `openUpdatePage` | Opens the configured update page directly. | | `addListener` | Fired for every successful status evaluation. | | `addListener` | Fired when the state resolves to `latest`. | | `addListener` | Fired when the state resolves to `outdated`. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-webview-version-checker](https://github.com/Cap-go/capacitor-webview-version-checker/). # Android Setup > Android-specific setup for @capgo/capacitor-webview-version-checker. This plugin is Android-first and performs native WebView provider version checks. ## Android support matrix [Section titled “Android support matrix”](#android-support-matrix) * API 22+ (Android 5.1 or later) * Android 5-6 and 10+: Android System WebView provider * Android 7-9: Google Chrome provider ## Default behavior (main use case) [Section titled “Default behavior (main use case)”](#default-behavior-main-use-case) The default mode is Browserslist-style compatibility: * `minimumDeviceSharePercent` defaults to `3` * dataset is bundled at build time from caniuse data * no runtime dataset URL call is required unless you set `versionShareApiUrl` ```ts import type { CapacitorConfig } from '@capacitor/cli'; const config: CapacitorConfig = { plugins: { WebviewVersionChecker: {}, }, }; export default config; ``` ## Basic plugin config [Section titled “Basic plugin config”](#basic-plugin-config) ```ts import type { CapacitorConfig } from '@capacitor/cli'; const config: CapacitorConfig = { plugins: { WebviewVersionChecker: { autoPromptOnOutdated: true, }, }, }; export default config; ``` ## Advanced threshold mode (custom dataset) [Section titled “Advanced threshold mode (custom dataset)”](#advanced-threshold-mode-custom-dataset) ```ts import type { CapacitorConfig } from '@capacitor/cli'; const config: CapacitorConfig = { plugins: { WebviewVersionChecker: { minimumDeviceSharePercent: 3, versionShareByMajor: { '137': 58.2, '136': 21.3, '135': 4.6, '134': 2.1, }, }, }, }; export default config; ``` `versionShareByMajor` explanation: * key = major WebView version (example `137`) * value = share percent (`0..100`) * `minimumDeviceSharePercent: 3` means “compatible only if current major version >= 3% share in the dataset” You can also provide the dataset through `versionShareApiUrl` with: * `{ "versionShareByMajor": { "137": 54.2, "136": 23.8 } }` * `{ "shareByMajor": { "137": 54.2, "136": 23.8 } }` * `{ "versions": [{ "major": 137, "share": 54.2 }, { "version": "136.0.0.0", "percent": 23.8 }] }` # Getting Started > Learn how to install and use WebView Version Checker in your Capacitor Android app. 1. **Install the package** ```sh bun add @capgo/capacitor-webview-version-checker ``` 2. **Sync native projects** ```sh bunx cap sync ``` 3. **Optional: add plugin config** You can run with defaults (`WebviewVersionChecker: {}`) or customize prompt and threshold behavior in `capacitor.config.ts`. ## Default behavior (main use case) [Section titled “Default behavior (main use case)”](#default-behavior-main-use-case) By default, this plugin uses a Browserslist-style compatibility rule: * `minimumDeviceSharePercent` defaults to `3` * the share dataset is bundled at build time from caniuse data * no runtime dataset URL call is needed for the default flow ```ts import type { CapacitorConfig } from '@capacitor/cli'; const config: CapacitorConfig = { plugins: { WebviewVersionChecker: {}, }, }; export default config; ``` ## Simple config-only setup (show native prompt) [Section titled “Simple config-only setup (show native prompt)”](#simple-config-only-setup-show-native-prompt) ```ts import type { CapacitorConfig } from '@capacitor/cli'; const config: CapacitorConfig = { plugins: { WebviewVersionChecker: { autoPromptOnOutdated: true, }, }, }; export default config; ``` ## Advanced threshold mode (custom dataset) [Section titled “Advanced threshold mode (custom dataset)”](#advanced-threshold-mode-custom-dataset) ```ts import type { CapacitorConfig } from '@capacitor/cli'; const config: CapacitorConfig = { plugins: { WebviewVersionChecker: { minimumDeviceSharePercent: 3, versionShareByMajor: { '137': 58.2, '136': 21.3, '135': 4.6, '134': 2.1, }, autoPromptOnOutdated: true, }, }, }; export default config; ``` Use this only if you want compatibility based on real-world share instead of only a fixed version. * `minimumDeviceSharePercent: 3` means the installed major version must represent at least 3% in your dataset. * `versionShareByMajor` is your custom map: major version => percentage. * If you prefer remote data, use `versionShareApiUrl` with one of: * `{ "versionShareByMajor": { "137": 54.2, "136": 23.8 } }` * `{ "shareByMajor": { "137": 54.2, "136": 23.8 } }` * `{ "versions": [{ "major": 137, "share": 54.2 }, { "version": "136.0.0.0", "percent": 23.8 }] }` ## Advanced usage with JavaScript [Section titled “Advanced usage with JavaScript”](#advanced-usage-with-javascript) ```ts import { WebviewVersionChecker } from '@capgo/capacitor-webview-version-checker'; await WebviewVersionChecker.addListener('webViewOutdated', (status) => { console.log('Outdated WebView detected', status); }); await WebviewVersionChecker.check({ minimumMajorVersion: 124, showPromptOnOutdated: true, }); ``` ## Why use this plugin instead of only Capacitor config [Section titled “Why use this plugin instead of only Capacitor config”](#why-use-this-plugin-instead-of-only-capacitor-config) Capacitor supports static minimum checks: ```ts android: { minWebViewVersion: 124, }, server: { errorPath: 'unsupported-webview.html', } ``` This plugin adds runtime events and native prompt UX, so users can still open and use the app while being encouraged to update. Evaluation order: 1. Device-share threshold mode (`minimumDeviceSharePercent` + dataset), if provided 2. Latest version mode (`latestVersion` / `latestVersionApiUrl`) 3. Minimum major fallback (`minimumMajorVersion`) ## Android provider handling [Section titled “Android provider handling”](#android-provider-handling) The plugin supports both WebView provider models used by Capacitor on Android: * Android 5-6 and 10+: Android System WebView (`com.google.android.webview`) * Android 7-9: Google Chrome (`com.android.chrome`) # iOS > iOS support notes for @capgo/capacitor-webview-version-checker. `@capgo/capacitor-webview-version-checker` currently targets Android runtime checks. ## Why [Section titled “Why”](#why) The plugin is designed for Android WebView provider compatibility flows: * Detect active WebView provider package and version * Compare against latest/minimum rules or device-share threshold * Offer native prompt routing to provider update destination iOS does not use the same update-provider model, so this plugin does not expose equivalent native enforcement there. # @capgo/capacitor-wechat > Capacitor WeChat Plugin - WeChat SDK integration for authentication, sharing, payments, and mini-programs. ## Overview [Section titled “Overview”](#overview) Capacitor WeChat Plugin - WeChat SDK integration for authentication, sharing, payments, and mini-programs. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `initialize` - Initialize the WeChat SDK with your application credentials. * `isInstalled` - Check if WeChat app is installed on the device. * `auth` - Authenticate user with WeChat OAuth. * `share` - Share content to WeChat. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | -------------------- | ------------------------------------------------------------ | | `initialize` | Initialize the WeChat SDK with your application credentials. | | `isInstalled` | Check if WeChat app is installed on the device. | | `auth` | Authenticate user with WeChat OAuth. | | `share` | Share content to WeChat. | | `sendPaymentRequest` | Send payment request to WeChat Pay. | | `openMiniProgram` | Open WeChat mini-program. | | `chooseInvoice` | Choose invoice from WeChat. | | `getPluginVersion` | Get the native Capacitor plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-wechat](https://github.com/Cap-go/capacitor-wechat/). # Getting Started > Install @capgo/capacitor-wechat and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-wechat bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { CapacitorWechat } from '@capgo/capacitor-wechat'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `initialize` [Section titled “initialize”](#initialize) Initialize the WeChat SDK with your application credentials. You can also set these values in `capacitor.config.ts` under the `CapacitorWechat` plugin configuration. Calling this method overrides any bundled configuration at runtime. ```typescript import { CapacitorWechat } from '@capgo/capacitor-wechat'; await CapacitorWechat.initialize({ appId: 'wx1234567890', universalLink: 'https://example.com/app/' }); ``` ### `isInstalled` [Section titled “isInstalled”](#isinstalled) Check if WeChat app is installed on the device. ```typescript import { CapacitorWechat } from '@capgo/capacitor-wechat'; const { installed } = await CapacitorWechat.isInstalled(); if (installed) { console.log('WeChat is installed'); } ``` ### `auth` [Section titled “auth”](#auth) Authenticate user with WeChat OAuth. ```typescript import { CapacitorWechat } from '@capgo/capacitor-wechat'; const { code, state } = await CapacitorWechat.auth({ scope: 'snsapi_userinfo', state: 'my_state' }); // Use code to get access token from your server ``` ### `share` [Section titled “share”](#share) Share content to WeChat. ```typescript import { CapacitorWechat } from '@capgo/capacitor-wechat'; // Share text await CapacitorWechat.share({ scene: 0, // 0 = Session, 1 = Timeline, 2 = Favorite type: 'text', text: 'Hello WeChat!' }); // Share link await CapacitorWechat.share({ scene: 1, type: 'link', title: 'My Website', description: 'Check out my website', link: 'https://example.com', imageUrl: 'https://example.com/image.jpg' }); ``` ### `sendPaymentRequest` [Section titled “sendPaymentRequest”](#sendpaymentrequest) Send payment request to WeChat Pay. ```typescript import { CapacitorWechat } from '@capgo/capacitor-wechat'; // Get payment params from your server first const paymentParams = await fetchPaymentParamsFromServer(); await CapacitorWechat.sendPaymentRequest({ partnerId: paymentParams.partnerId, prepayId: paymentParams.prepayId, nonceStr: paymentParams.nonceStr, timeStamp: paymentParams.timeStamp, package: paymentParams.package, sign: paymentParams.sign }); ``` ### `openMiniProgram` [Section titled “openMiniProgram”](#openminiprogram) Open WeChat mini-program. ```typescript import { CapacitorWechat } from '@capgo/capacitor-wechat'; const { extMsg } = await CapacitorWechat.openMiniProgram({ username: 'gh_xxxxxxxxxxxxx', path: 'pages/index/index', type: 0 // 0 = Release, 1 = Test, 2 = Preview }); ``` ### `chooseInvoice` [Section titled “chooseInvoice”](#chooseinvoice) Choose invoice from WeChat. ```typescript import { CapacitorWechat } from '@capgo/capacitor-wechat'; const { cards } = await CapacitorWechat.chooseInvoice({ appId: 'your_app_id', signType: 'SHA1', cardSign: 'signature', timeStamp: '1234567890', nonceStr: 'random_string' }); console.log('Selected cards:', cards); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `WechatInitializationOptions` [Section titled “WechatInitializationOptions”](#wechatinitializationoptions) WeChat initialization options. ```typescript export interface WechatInitializationOptions { /** * Required WeChat application ID. */ appId: string; /** * iOS universal link that is associated with your WeChat application. */ universalLink?: string; } ``` ### `WechatAuthOptions` [Section titled “WechatAuthOptions”](#wechatauthoptions) WeChat authentication options. ```typescript export interface WechatAuthOptions { /** * OAuth scope. Use 'snsapi_userinfo' for user info or 'snsapi_login' for login only. */ scope: string; /** * Optional state parameter for CSRF protection. */ state?: string; } ``` ### `WechatAuthResponse` [Section titled “WechatAuthResponse”](#wechatauthresponse) WeChat authentication response. ```typescript export interface WechatAuthResponse { /** * Authorization code to exchange for access token. */ code: string; /** * State parameter if provided in request. */ state?: string; } ``` ### `WechatShareOptions` [Section titled “WechatShareOptions”](#wechatshareoptions) WeChat share options. ```typescript export interface WechatShareOptions { /** * Share scene: 0 = Session (chat), 1 = Timeline (moments), 2 = Favorite. */ scene: number; /** * Share type: 'text', 'image', 'link', 'music', 'video', 'miniprogram'. */ type: 'text' | 'image' | 'link' | 'music' | 'video' | 'miniprogram'; /** * Text content (for type 'text'). */ text?: string; /** * Title (for type 'link', 'music', 'video', 'miniprogram'). */ title?: string; /** * Description (for type 'link', 'music', 'video', 'miniprogram'). */ description?: string; /** * Link URL (for type 'link'). */ link?: string; /** * Image URL or base64 data. */ imageUrl?: string; /** * Thumbnail URL or base64 data (for type 'link', 'music', 'video'). */ thumbUrl?: string; /** * Music or video URL (for type 'music', 'video'). */ mediaUrl?: string; /** * Mini-program username (for type 'miniprogram'). */ miniProgramUsername?: string; /** * Mini-program path (for type 'miniprogram'). */ miniProgramPath?: string; /** * Mini-program type: 0 = Release, 1 = Test, 2 = Preview (for type 'miniprogram'). */ miniProgramType?: number; /** * Mini-program web page URL fallback (for type 'miniprogram'). */ miniProgramWebPageUrl?: string; } ``` ### `WechatPaymentOptions` [Section titled “WechatPaymentOptions”](#wechatpaymentoptions) WeChat payment options. ```typescript export interface WechatPaymentOptions { /** * Partner ID (merchant ID). */ partnerId: string; /** * Prepay ID from unified order API. */ prepayId: string; /** * Random string. */ nonceStr: string; /** * Timestamp. */ timeStamp: string; /** * Package value, typically 'Sign=WXPay'. */ package: string; /** * Signature. */ sign: string; } ``` ### `WechatMiniProgramOptions` [Section titled “WechatMiniProgramOptions”](#wechatminiprogramoptions) WeChat mini-program options. ```typescript export interface WechatMiniProgramOptions { /** * Mini-program username (original ID). */ username: string; /** * Path to open in mini-program. */ path?: string; /** * Mini-program type: 0 = Release, 1 = Test, 2 = Preview. */ type?: number; } ``` ### `WechatInvoiceOptions` [Section titled “WechatInvoiceOptions”](#wechatinvoiceoptions) WeChat invoice options. ```typescript export interface WechatInvoiceOptions { /** * App ID. */ appId: string; /** * Signature type. */ signType: string; /** * Card signature. */ cardSign: string; /** * Timestamp. */ timeStamp: string; /** * Random string. */ nonceStr: string; } ``` ### `WechatInvoiceResponse` [Section titled “WechatInvoiceResponse”](#wechatinvoiceresponse) WeChat invoice response. ```typescript export interface WechatInvoiceResponse { /** * Array of selected card IDs. */ cards: WechatInvoiceCard[]; } ``` ### `WechatInvoiceCard` [Section titled “WechatInvoiceCard”](#wechatinvoicecard) WeChat invoice card item. ```typescript export interface WechatInvoiceCard { /** * The selected card identifier. */ cardId: string; /** * Encrypted code returned by WeChat. */ encryptCode?: string; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-widget-kit > WidgetKit and Live Activities for Capacitor apps, with SVG-driven templates or full-native widget state sync. ## Overview [Section titled “Overview”](#overview) `@capgo/capacitor-widget-kit` gives a Capacitor app two ways to drive widgets and Live Activities: * SVG template activities: define WidgetKit surfaces as SVG, switch named frames from taps, run pause/play timers, mutate JSON state, and collect action events in the app. * Full-native widget sessions: keep the widget UI fully in Swift/Kotlin/Java while Capacitor owns shared JSON state and app-to-widget or widget-to-app messages. Use SVG templates when your widget can be rendered from resolved SVG strings. Use full-native sessions when the widget needs a custom native UI but still has to start, stop, sync state, or ask the app to complete async work. ## Choose A Mode [Section titled “Choose A Mode”](#choose-a-mode) | Mode | Best for | Main APIs | | -------------------------- | -------------------------------------------------------------- | ---------------------------------------------------------------------- | | SVG template activity | Live Activities or widget surfaces that render from SVG output | `startTemplateActivity`, `performTemplateAction`, `listTemplateEvents` | | Full-native widget session | Native-rendered widgets that need shared state and async jobs | `startWidgetSession`, `updateWidgetSession`, `sendWidgetMessage` | Both modes can live in the same app. For example, a workout app can use an SVG Live Activity for fast frame/timer controls and a full-native widget session for a home-screen widget with a richer native layout. ## SVG Template Capabilities [Section titled “SVG Template Capabilities”](#svg-template-capabilities) SVG templates include the pieces needed for interactive widget surfaces: * `frames` hold named SVG variants such as `summary`, `timer`, or `details`. * `frameMutations` switch, toggle, or step through frames after a hotspot action. * `timerMutations` start, pause, resume, toggle, reset, stop, or change timer duration. * `patches` update JSON state using literal values, templates, timestamps, increments, toggles, or unset operations. * `hotspots` map tap areas to action identifiers. * `listTemplateEvents` lets the app process widget-originated actions later. The runtime resolves placeholders like `{{state.title}}`, `{{timers.rest.remainingText}}`, and `{{meta.template.kind}}` before the native bridge returns a surface for rendering. ## Full-Native Bridge Capabilities [Section titled “Full-Native Bridge Capabilities”](#full-native-bridge-capabilities) Full-native sessions are for widgets that render their own UI natively: * `startWidgetSession` creates shared state and metadata for native widget code. * `updateWidgetSession` merges or replaces state and marks the session active again. * `stopWidgetSession` records a final state and marks the session stopped. * `sendWidgetMessage` queues app-to-widget or widget-to-app work. * `acknowledgeWidgetMessages` marks messages as received. * `completeWidgetMessage` stores a response or failure for async jobs. Messages are idempotent after completion: retrying a completed or failed message returns the existing result instead of overwriting it. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | --------------------------- | --------------------------------------------------------------------------------- | | `areActivitiesSupported` | Check whether the native template activity bridge can run on the current device. | | `startTemplateActivity` | Persist an SVG template activity and start the native Live Activity bridge. | | `updateTemplateActivity` | Replace the activity definition, state, or open URL. | | `endTemplateActivity` | End a running activity and optionally persist one last state snapshot. | | `performTemplateAction` | Execute declarative patches, frame mutations, timer mutations, and event logging. | | `getTemplateActivity` | Read one stored template activity. | | `listTemplateActivities` | List every stored template activity. | | `listTemplateEvents` | Read action events emitted by template actions. | | `acknowledgeTemplateEvents` | Mark template events as processed. | | `startWidgetSession` | Start a full-native widget session backed by shared JSON state. | | `updateWidgetSession` | Merge or replace a full-native widget session state. | | `stopWidgetSession` | Stop a full-native widget session and optionally persist final state. | | `getWidgetSession` | Read one full-native widget session. | | `listWidgetSessions` | List every full-native widget session. | | `sendWidgetMessage` | Queue a message between the app and native widget code. | | `listWidgetMessages` | List queued bridge messages. | | `acknowledgeWidgetMessages` | Mark bridge messages as acknowledged. | | `completeWidgetMessage` | Complete or fail an async bridge message. | | `getPluginVersion` | Return the platform implementation version marker. | ## Native Pieces [Section titled “Native Pieces”](#native-pieces) The plugin also ships native helpers for widget targets: * `CapgoTemplateWidgetBridge` resolves an SVG template surface into `svg`, `frameId`, `hotspots`, and metadata. * `CapgoTemplateActionIntent` connects interactive iOS widget buttons to template actions. * `CapgoNativeWidgetBridge` loads full-native sessions and messages from native widget code. * Android template helpers provide matching action receiver and widget bridge behavior. ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) The API reference is synced from [`src/definitions.ts`](https://github.com/Cap-go/capacitor-widget-kit/blob/main/src/definitions.ts) in the plugin repository. # Getting Started > Install @capgo/capacitor-widget-kit, create SVG frame/timer widgets, or sync full-native widgets with the app. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-widget-kit bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { CapgoWidgetKit } from '@capgo/capacitor-widget-kit'; ``` ## iOS Setup [Section titled “iOS Setup”](#ios-setup) For Live Activities and WidgetKit extensions, configure the native app first: * Use iOS 17+ for interactive Live Activity buttons when possible. * Add `NSSupportsLiveActivities` to the app `Info.plist` when using ActivityKit. * Add the same App Group to the app target and the widget extension target. * Set `CapgoWidgetKitAppGroup` in both `Info.plist` files to the shared App Group identifier. ```xml <key>CapgoWidgetKitAppGroup</key> <string>group.app.capgo.widgetkit.exampleapp.widgetkit</string> ``` ## Check Support [Section titled “Check Support”](#check-support) ```typescript const { supported, reason } = await CapgoWidgetKit.areActivitiesSupported(); if (!supported) { console.log('WidgetKit bridge unavailable:', reason); } ``` ## Option 1: SVG Template Activity [Section titled “Option 1: SVG Template Activity”](#option-1-svg-template-activity) Use this mode when the widget can render resolved SVG. The plugin stores state, resolves placeholders, applies tap actions, switches SVG frames, and keeps timer state consistent. ```typescript const { activity } = await CapgoWidgetKit.startTemplateActivity({ activityId: 'workout-session-1', openUrl: 'myapp://workout/session-1', state: { title: 'Chest Day', frame: 'summary', restDurationMs: 90000, }, definition: { id: 'workout-card', timers: [ { id: 'rest', durationPath: 'state.restDurationMs', }, ], actions: [ { id: 'next-frame', eventName: 'widget.frame.changed', frameMutations: [ { op: 'next', path: 'frame', surface: 'lockScreen', }, ], }, { id: 'toggle-rest', eventName: 'widget.timer.toggled', timerMutations: [ { op: 'toggle', timerId: 'rest', }, ], }, ], layouts: { lockScreen: { width: 100, height: 40, frameIdPath: 'state.frame', frames: [ { id: 'summary', hotspots: [{ id: 'switch', actionId: 'next-frame', x: 0, y: 0, width: 100, height: 40 }], svg: `<svg viewBox="0 0 100 40"><text x="6" y="22">{{state.title}}</text></svg>`, }, { id: 'timer', hotspots: [{ id: 'pause-play', actionId: 'toggle-rest', x: 0, y: 0, width: 100, height: 40 }], svg: `<svg viewBox="0 0 100 40"><text x="6" y="22">{{timers.rest.remainingText}}</text></svg>`, }, ], }, }, }, }); ``` ### Run Actions From The App [Section titled “Run Actions From The App”](#run-actions-from-the-app) Native widgets can trigger the same actions through their hotspot/action wiring. The app can also run them directly: ```typescript await CapgoWidgetKit.performTemplateAction({ activityId: activity.activityId, actionId: 'toggle-rest', sourceId: 'app-pause-play-button', }); ``` ### Process Widget Events [Section titled “Process Widget Events”](#process-widget-events) Actions emit events so the app can process widget interactions after launch or resume: ```typescript const { events } = await CapgoWidgetKit.listTemplateEvents({ activityId: activity.activityId, unacknowledgedOnly: true, }); for (const event of events) { console.log('Widget event:', event.eventName, event.state, event.timers); } await CapgoWidgetKit.acknowledgeTemplateEvents({ activityId: activity.activityId, }); ``` ### Update Or End The Activity [Section titled “Update Or End The Activity”](#update-or-end-the-activity) ```typescript await CapgoWidgetKit.updateTemplateActivity({ activityId: activity.activityId, state: { title: 'Back Day', frame: 'summary', restDurationMs: 120000, }, }); await CapgoWidgetKit.endTemplateActivity({ activityId: activity.activityId, state: { title: 'Workout complete', frame: 'summary' }, }); ``` ## Frame Mutations [Section titled “Frame Mutations”](#frame-mutations) Frame mutations write the active frame id into state. A layout can then read it with `frameIdPath`. | Operation | Behavior | | ---------- | ---------------------------------------------------------------------------------------------------------------- | | `set` | Set a specific frame id. Plain strings are treated as literal frame ids; `{{...}}` templates are resolved first. | | `next` | Move to the next frame from `frameIds` or the frames declared on `surface`. | | `previous` | Move to the previous frame. | | `toggle` | Toggle between the first two available frames, or between the current frame and `frameId`. | Invalid frame ids are ignored when the mutation has a known selectable frame list, so state stays aligned with the rendered surface. ## Timer Mutations [Section titled “Timer Mutations”](#timer-mutations) Timer mutations target a named timer from `definition.timers`. | Operation | Behavior | | ------------------- | ------------------------------------------------------------------------------------------ | | `start` / `restart` | Start from zero using the current duration. | | `pause` | Store elapsed time and clear `startedAt`. | | `resume` | Resume only paused timers. Stopped timers stay stopped until an explicit start or restart. | | `toggle` | Pause a running timer or resume a paused timer. | | `reset` | Clear elapsed time and return to idle. | | `stop` | Clear runtime progress and mark the timer stopped. | | `setDuration` | Recompute status after a duration change. | Timer bindings are available to SVG as `{{timers.<id>.remainingText}}`, `{{timers.<id>.elapsedMs}}`, `{{timers.<id>.status}}`, and related fields. ## Option 2: Full-Native Widget Session [Section titled “Option 2: Full-Native Widget Session”](#option-2-full-native-widget-session) Use this mode when the widget UI is built in native code. The plugin gives the app and widget a shared session record and a message queue. ```typescript const { session } = await CapgoWidgetKit.startWidgetSession({ widgetId: 'native-session-1', kind: 'workout-controls', state: { isRunning: true, selectedSetId: 'set-1' }, metadata: { accent: '#00d69c' }, }); await CapgoWidgetKit.updateWidgetSession({ widgetId: session.widgetId, merge: true, state: { isRunning: false }, }); const { sessions } = await CapgoWidgetKit.listWidgetSessions(); console.log('Known widget sessions:', sessions); ``` ## Async Widget Messages [Section titled “Async Widget Messages”](#async-widget-messages) Messages cover work that needs a later response, such as a widget asking the app to sync data. ```typescript const { message } = await CapgoWidgetKit.sendWidgetMessage({ widgetId: session.widgetId, direction: 'widgetToApp', name: 'syncWorkoutSet', payload: { setId: 'set-1' }, expectsResponse: true, }); await CapgoWidgetKit.acknowledgeWidgetMessages({ messageIds: [message.messageId], }); await CapgoWidgetKit.completeWidgetMessage({ messageId: message.messageId, response: { synced: true }, }); ``` To fail the job, pass `error` instead of `response`: ```typescript await CapgoWidgetKit.completeWidgetMessage({ messageId: message.messageId, error: 'Network unavailable', }); ``` `completeWidgetMessage` is idempotent. If the message is already completed or failed, repeated calls return the existing message snapshot. ## Stop A Native Session [Section titled “Stop A Native Session”](#stop-a-native-session) ```typescript await CapgoWidgetKit.stopWidgetSession({ widgetId: session.widgetId, state: { isRunning: false }, }); ``` ## API Groups [Section titled “API Groups”](#api-groups) | Group | APIs | | ---------------------- | ------------------------------------------------------------------------------------------------------------------------- | | Capability | `areActivitiesSupported`, `getPluginVersion` | | SVG activity lifecycle | `startTemplateActivity`, `updateTemplateActivity`, `endTemplateActivity`, `getTemplateActivity`, `listTemplateActivities` | | SVG actions and events | `performTemplateAction`, `listTemplateEvents`, `acknowledgeTemplateEvents` | | Native widget sessions | `startWidgetSession`, `updateWidgetSession`, `stopWidgetSession`, `getWidgetSession`, `listWidgetSessions` | | Native widget messages | `sendWidgetMessage`, `listWidgetMessages`, `acknowledgeWidgetMessages`, `completeWidgetMessage` | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) The full type reference lives in the plugin repository at [`src/definitions.ts`](https://github.com/Cap-go/capacitor-widget-kit/blob/main/src/definitions.ts). # @capgo/capacitor-wifi > WiFi plugin for managing device WiFi connectivity. ## Overview [Section titled “Overview”](#overview) WiFi plugin for managing device WiFi connectivity. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `addNetwork` - Show a system dialog to add a Wi-Fi network to the device. On Android SDK 30+, this opens the system Wi-Fi settings with the network pre-filled. On iOS, this connects to the network directly. * `connect` - Connect to a Wi-Fi network. On Android, this creates a temporary connection that doesn’t route traffic through the network by default. Set autoRouteTraffic to true to bind app traffic to the connected network (useful for local/device-hosted APs). For a persistent connection on Android, use addNetwork() instead. On iOS, this creates a persistent connection. * `disconnect` - Disconnect from the current Wi-Fi network. On iOS, only disconnects from networks that were added via this plugin. * `getAvailableNetworks` - Get a list of available Wi-Fi networks from the last scan. Only available on Android. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `addNetwork` | Show a system dialog to add a Wi-Fi network to the device. On Android SDK 30+, this opens the system Wi-Fi settings with the network pre-filled. On iOS, this connects to the network directly. | | `connect` | Connect to a Wi-Fi network. On Android, this creates a temporary connection that doesn’t route traffic through the network by default. Set autoRouteTraffic to true to bind app traffic to the connected network (useful for local/device-hosted APs). For a persistent connection on Android, use addNetwork() instead. On iOS, this creates a persistent connection. | | `disconnect` | Disconnect from the current Wi-Fi network. On iOS, only disconnects from networks that were added via this plugin. | | `getAvailableNetworks` | Get a list of available Wi-Fi networks from the last scan. Only available on Android. | | `getIpAddress` | Get the device’s current IP address. Available on both Android and iOS. | | `getRssi` | Get the received signal strength indicator (RSSI) of the current network in dBm. Only available on Android. | | `getSsid` | Get the service set identifier (SSID) of the current network. Available on both Android and iOS. | | `getWifiInfo` | Get comprehensive information about the currently connected WiFi network. This method provides detailed network information including SSID, BSSID, IP address, frequency, link speed, and signal strength in a single call. On iOS, some fields may not be available and will be undefined. | | `isEnabled` | Check if Wi-Fi is enabled on the device. Only available on Android. | | `startScan` | Start scanning for Wi-Fi networks. Only available on Android. Results are delivered via the ‘networksScanned’ event listener. Note: May fail due to system throttling or hardware issues. | | `checkPermissions` | Check the current permission status for location access. Location permission is required for Wi-Fi operations on both platforms. | | `requestPermissions` | Request location permissions from the user. Location permission is required for Wi-Fi operations on both platforms. | | `addListener` | Add a listener for the ‘networksScanned’ event. Only available on Android. This event is fired when Wi-Fi scan results are available. | | `removeAllListeners` | Remove all listeners for this plugin. | | `getPluginVersion` | Get the native plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-wifi](https://github.com/Cap-go/capacitor-wifi/). # Getting Started > Install @capgo/capacitor-wifi and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-wifi bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { CapacitorWifi } from '@capgo/capacitor-wifi'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `addNetwork` [Section titled “addNetwork”](#addnetwork) Show a system dialog to add a Wi-Fi network to the device. On Android SDK 30+, this opens the system Wi-Fi settings with the network pre-filled. On iOS, this connects to the network directly. ```typescript import { CapacitorWifi } from '@capgo/capacitor-wifi'; await CapacitorWifi.addNetwork({ ssid: 'MyNetwork', password: 'mypassword', isHiddenSsid: false, securityType: NetworkSecurityType.WPA2_PSK }); ``` ### `connect` [Section titled “connect”](#connect) Connect to a Wi-Fi network. On Android, this creates a temporary connection that doesn’t route traffic through the network by default. Set autoRouteTraffic to true to bind app traffic to the connected network (useful for local/device-hosted APs). For a persistent connection on Android, use addNetwork() instead. On iOS, this creates a persistent connection. ```typescript import { CapacitorWifi } from '@capgo/capacitor-wifi'; await CapacitorWifi.connect({ ssid: 'MyNetwork', password: 'mypassword', autoRouteTraffic: true // Android only: route app traffic through this network }); ``` ### `disconnect` [Section titled “disconnect”](#disconnect) Disconnect from the current Wi-Fi network. On iOS, only disconnects from networks that were added via this plugin. ```typescript import { CapacitorWifi } from '@capgo/capacitor-wifi'; await CapacitorWifi.disconnect(); ``` ### `getAvailableNetworks` [Section titled “getAvailableNetworks”](#getavailablenetworks) Get a list of available Wi-Fi networks from the last scan. Only available on Android. ```typescript import { CapacitorWifi } from '@capgo/capacitor-wifi'; const { networks } = await CapacitorWifi.getAvailableNetworks(); networks.forEach(network => { console.log(`SSID: ${network.ssid}, Signal: ${network.rssi} dBm`); }); ``` ### `getIpAddress` [Section titled “getIpAddress”](#getipaddress) Get the device’s current IP address. Available on both Android and iOS. ```typescript import { CapacitorWifi } from '@capgo/capacitor-wifi'; const { ipAddress } = await CapacitorWifi.getIpAddress(); console.log('IP Address:', ipAddress); ``` ### `getRssi` [Section titled “getRssi”](#getrssi) Get the received signal strength indicator (RSSI) of the current network in dBm. Only available on Android. ```typescript import { CapacitorWifi } from '@capgo/capacitor-wifi'; const { rssi } = await CapacitorWifi.getRssi(); console.log('Signal strength:', rssi, 'dBm'); ``` ### `getSsid` [Section titled “getSsid”](#getssid) Get the service set identifier (SSID) of the current network. Available on both Android and iOS. ```typescript import { CapacitorWifi } from '@capgo/capacitor-wifi'; const { ssid } = await CapacitorWifi.getSsid(); console.log('Connected to:', ssid); ``` ### `getWifiInfo` [Section titled “getWifiInfo”](#getwifiinfo) Get comprehensive information about the currently connected WiFi network. This method provides detailed network information including SSID, BSSID, IP address, frequency, link speed, and signal strength in a single call. On iOS, some fields may not be available and will be undefined. ```typescript import { CapacitorWifi } from '@capgo/capacitor-wifi'; const info = await CapacitorWifi.getWifiInfo(); console.log('Network:', info.ssid); console.log('BSSID:', info.bssid); console.log('IP:', info.ip); console.log('Frequency:', info.frequency, 'MHz'); console.log('Speed:', info.linkSpeed, 'Mbps'); console.log('Signal:', info.signalStrength); ``` ### `isEnabled` [Section titled “isEnabled”](#isenabled) Check if Wi-Fi is enabled on the device. Only available on Android. ```typescript import { CapacitorWifi } from '@capgo/capacitor-wifi'; const { enabled } = await CapacitorWifi.isEnabled(); console.log('WiFi is', enabled ? 'enabled' : 'disabled'); ``` ### `startScan` [Section titled “startScan”](#startscan) Start scanning for Wi-Fi networks. Only available on Android. Results are delivered via the ‘networksScanned’ event listener. Note: May fail due to system throttling or hardware issues. ```typescript import { CapacitorWifi } from '@capgo/capacitor-wifi'; await CapacitorWifi.addListener('networksScanned', () => { console.log('Scan completed'); }); await CapacitorWifi.startScan(); ``` ### `checkPermissions` [Section titled “checkPermissions”](#checkpermissions) Check the current permission status for location access. Location permission is required for Wi-Fi operations on both platforms. ```typescript import { CapacitorWifi } from '@capgo/capacitor-wifi'; const status = await CapacitorWifi.checkPermissions(); console.log('Location permission:', status.location); ``` ### `requestPermissions` [Section titled “requestPermissions”](#requestpermissions) Request location permissions from the user. Location permission is required for Wi-Fi operations on both platforms. ```typescript import { CapacitorWifi } from '@capgo/capacitor-wifi'; const status = await CapacitorWifi.requestPermissions(); if (status.location === 'granted') { console.log('Permission granted'); } ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `AddNetworkOptions` [Section titled “AddNetworkOptions”](#addnetworkoptions) Options for adding a network. ```typescript export interface AddNetworkOptions { /** * The SSID of the network to add * * @since 7.0.0 */ ssid: string; /** * The password for the network (optional for open networks) * * @since 7.0.0 */ password?: string; /** * Whether the network is hidden (Android only) * * @since 7.0.0 * @default false */ isHiddenSsid?: boolean; /** * The security type of the network (Android only) * * @since 7.0.0 * @default NetworkSecurityType.WPA2_PSK */ securityType?: NetworkSecurityType; } ``` ### `ConnectOptions` [Section titled “ConnectOptions”](#connectoptions) Options for connecting to a network. ```typescript export interface ConnectOptions { /** * The SSID of the network to connect to * * @since 7.0.0 */ ssid: string; /** * The password for the network (optional for open networks) * * @since 7.0.0 */ password?: string; /** * Whether the network is hidden (Android only) * * @since 7.0.0 * @default false */ isHiddenSsid?: boolean; /** * Whether to automatically route app traffic through the connected Wi-Fi network (Android only) * When enabled, it binds the app process to the connected network using ConnectivityManager.bindProcessToNetwork() * This is useful for connecting to local/device-hosted APs (e.g., ESP32, IoT devices) that don't have internet access. * * @since 7.0.0 * @default false */ autoRouteTraffic?: boolean; } ``` ### `DisconnectOptions` [Section titled “DisconnectOptions”](#disconnectoptions) Options for disconnecting from a network. ```typescript export interface DisconnectOptions { /** * The SSID of the network to disconnect from (optional) * * @since 7.0.0 */ ssid?: string; } ``` ### `GetAvailableNetworksResult` [Section titled “GetAvailableNetworksResult”](#getavailablenetworksresult) Result from getAvailableNetworks(). ```typescript export interface GetAvailableNetworksResult { /** * List of available networks * * @since 7.0.0 */ networks: Network[]; } ``` ### `GetIpAddressResult` [Section titled “GetIpAddressResult”](#getipaddressresult) Result from getIpAddress(). ```typescript export interface GetIpAddressResult { /** * The device's IP address * * @since 7.0.0 */ ipAddress: string; } ``` ### `GetRssiResult` [Section titled “GetRssiResult”](#getrssiresult) Result from getRssi(). ```typescript export interface GetRssiResult { /** * The signal strength in dBm * * @since 7.0.0 */ rssi: number; } ``` ### `GetSsidResult` [Section titled “GetSsidResult”](#getssidresult) Result from getSsid(). ```typescript export interface GetSsidResult { /** * The SSID of the current network * * @since 7.0.0 */ ssid: string; } ``` ### `WifiInfo` [Section titled “WifiInfo”](#wifiinfo) Comprehensive WiFi information. ```typescript export interface WifiInfo { /** * The SSID (network name) of the current network * * @since 7.0.0 */ ssid: string; /** * The BSSID (MAC address) of the access point. * Not available on iOS. * * @since 7.0.0 */ bssid?: string; /** * The device's IP address on the network * * @since 7.0.0 */ ip: string; /** * The network frequency in MHz. * Not available on iOS. * * @since 7.0.0 */ frequency?: number; /** * The connection speed in Mbps. * Not available on iOS. * * @since 7.0.0 */ linkSpeed?: number; /** * The signal strength (0-100). * Calculated from RSSI on Android. * Not available on iOS. * * @since 7.0.0 */ signalStrength?: number; } ``` ### `IsEnabledResult` [Section titled “IsEnabledResult”](#isenabledresult) Result from isEnabled(). ```typescript export interface IsEnabledResult { /** * Whether Wi-Fi is enabled * * @since 7.0.0 */ enabled: boolean; } ``` ### `PermissionStatus` [Section titled “PermissionStatus”](#permissionstatus) Permission status. ```typescript export interface PermissionStatus { /** * Location permission state * * @since 7.0.0 */ location: PermissionState; } ``` ### `RequestPermissionsOptions` [Section titled “RequestPermissionsOptions”](#requestpermissionsoptions) Options for requesting permissions. ```typescript export interface RequestPermissionsOptions { /** * Permissions to request * * @since 7.0.0 */ permissions?: 'location'[]; } ``` ### `NetworkSecurityType` [Section titled “NetworkSecurityType”](#networksecuritytype) Network security types. ```typescript export enum NetworkSecurityType { /** * Open network with no security * * @since 7.0.0 */ OPEN = 0, /** * WEP security * * @since 7.0.0 */ WEP = 1, /** * WPA/WPA2 Personal (PSK) * * @since 7.0.0 */ WPA2_PSK = 2, /** * WPA/WPA2/WPA3 Enterprise (EAP) * * @since 7.0.0 */ EAP = 3, /** * WPA3 Personal (SAE) * * @since 7.0.0 */ SAE = 4, /** * WPA3 Enterprise * * @since 7.0.0 */ WPA3_ENTERPRISE = 5, /** * WPA3 Enterprise 192-bit mode * * @since 7.0.0 */ WPA3_ENTERPRISE_192_BIT = 6, /** * Passpoint network * * @since 7.0.0 */ PASSPOINT = 7, /** * Enhanced Open (OWE) * * @since 7.0.0 */ OWE = 8, /** * WAPI PSK * * @since 7.0.0 */ WAPI_PSK = 9, /** * WAPI Certificate * * @since 7.0.0 */ WAPI_CERT = 10, } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-youtube-player > YouTube Player Plugin interface for Capacitor. Provides methods to control YouTube video playback in your app. ## Overview [Section titled “Overview”](#overview) YouTube Player Plugin interface for Capacitor. Provides methods to control YouTube video playback in your app. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `initialize` - Initialize a new YouTube player instance. * `destroy` - Destroy a player instance and free resources. * `stopVideo` - Stop video playback and cancel loading. Use this sparingly - pauseVideo() is usually preferred. * `playVideo` - Play the currently cued or loaded video. Final player state will be PLAYING (1). ## Public API [Section titled “Public API”](#public-api) | Method | Description | | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | | `initialize` | Initialize a new YouTube player instance. | | `destroy` | Destroy a player instance and free resources. | | `stopVideo` | Stop video playback and cancel loading. Use this sparingly - pauseVideo() is usually preferred. | | `playVideo` | Play the currently cued or loaded video. Final player state will be PLAYING (1). | | `pauseVideo` | Pause the currently playing video. Final player state will be PAUSED (2), unless already ENDED (0). | | `seekTo` | Seek to a specific time in the video. If player is paused, it remains paused. If playing, continues playing. | | `loadVideoById` | Load and play a video by its YouTube ID. | | `cueVideoById` | Cue a video by ID without playing it. Loads thumbnail and prepares player, but doesn’t request video until playVideo() called. | | `loadVideoByUrl` | Load and play a video by its full URL. | | `cueVideoByUrl` | Cue a video by URL without playing it. | | `cuePlaylist` | Cue a playlist without playing it. Loads playlist and prepares first video. | | `loadPlaylist` | Load and play a playlist. | | `nextVideo` | Play the next video in the playlist. | | `previousVideo` | Play the previous video in the playlist. | | `playVideoAt` | Play a specific video in the playlist by index. | | `mute` | Mute the player audio. | | `unMute` | Unmute the player audio. | | `isMuted` | Check if the player is currently muted. | | `setVolume` | Set the player volume level. | | `getVolume` | Get the current player volume level. Returns volume even if player is muted. | | `setSize` | Set the player dimensions in pixels. | | `getPlaybackRate` | Get the current playback rate. | | `setPlaybackRate` | Set the playback speed. | | `getAvailablePlaybackRates` | Get list of available playback rates for current video. | | `setLoop` | Enable or disable playlist looping. When enabled, playlist will restart from beginning after last video. | | `setShuffle` | Enable or disable playlist shuffle. | | `getVideoLoadedFraction` | Get the fraction of the video that has been buffered. More reliable than deprecated getVideoBytesLoaded/getVideoBytesTotal. | | `getPlayerState` | Get the current state of the player. | | `getAllPlayersEventsState` | Get event states for all active players. Useful for tracking multiple player instances. | | `getCurrentTime` | Get the current playback position in seconds. | | `toggleFullScreen` | Toggle fullscreen mode on or off. | | `getPlaybackQuality` | Get the current playback quality. | | `setPlaybackQuality` | Set the suggested playback quality. Actual quality may differ based on network conditions. | | `getAvailableQualityLevels` | Get list of available quality levels for current video. | | `getDuration` | Get the duration of the current video in seconds. | | `getVideoUrl` | Get the YouTube.com URL for the current video. | | `getVideoEmbedCode` | Get the embed code for the current video. Returns HTML iframe embed code. | | `getPlaylist` | Get array of video IDs in the current playlist. | | `getPlaylistIndex` | Get the index of the currently playing video in the playlist. | | `getIframe` | Get the iframe DOM element for the player. Web platform only. | | `addEventListener` | Add an event listener to the player. Web platform only. | | `removeEventListener` | Remove an event listener from the player. Web platform only. | | `getPluginVersion` | Get the plugin version number. Returns platform-specific version information. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-youtube-player](https://github.com/Cap-go/capacitor-youtube-player/). # Getting Started > Install @capgo/capacitor-youtube-player and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-youtube-player bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { YoutubePlayer } from '@capgo/capacitor-youtube-player'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `initialize` [Section titled “initialize”](#initialize) Initialize a new YouTube player instance. ```typescript import { YoutubePlayer } from '@capgo/capacitor-youtube-player'; await YoutubePlayer.initialize({ playerId: 'my-player', videoId: 'dQw4w9WgXcQ', playerSize: { width: 640, height: 360 }, privacyEnhanced: true }); ``` ### `destroy` [Section titled “destroy”](#destroy) Destroy a player instance and free resources. ```typescript import { YoutubePlayer } from '@capgo/capacitor-youtube-player'; await YoutubePlayer.destroy({} as PlayerIdOptions); ``` ### `stopVideo` [Section titled “stopVideo”](#stopvideo) Stop video playback and cancel loading. Use this sparingly - pauseVideo() is usually preferred. ```typescript import { YoutubePlayer } from '@capgo/capacitor-youtube-player'; await YoutubePlayer.stopVideo({} as PlayerIdOptions); ``` ### `playVideo` [Section titled “playVideo”](#playvideo) Play the currently cued or loaded video. Final player state will be PLAYING (1). ```typescript import { YoutubePlayer } from '@capgo/capacitor-youtube-player'; await YoutubePlayer.playVideo({} as PlayerIdOptions); ``` ### `pauseVideo` [Section titled “pauseVideo”](#pausevideo) Pause the currently playing video. Final player state will be PAUSED (2), unless already ENDED (0). ```typescript import { YoutubePlayer } from '@capgo/capacitor-youtube-player'; await YoutubePlayer.pauseVideo({} as PlayerIdOptions); ``` ### `seekTo` [Section titled “seekTo”](#seekto) Seek to a specific time in the video. If player is paused, it remains paused. If playing, continues playing. ```typescript import { YoutubePlayer } from '@capgo/capacitor-youtube-player'; await YoutubePlayer.seekTo({} as SeekToOptions); ``` ### `loadVideoById` [Section titled “loadVideoById”](#loadvideobyid) Load and play a video by its YouTube ID. ```typescript import { YoutubePlayer } from '@capgo/capacitor-youtube-player'; await YoutubePlayer.loadVideoById({} as VideoByIdMethodOptions); ``` ### `cueVideoById` [Section titled “cueVideoById”](#cuevideobyid) Cue a video by ID without playing it. Loads thumbnail and prepares player, but doesn’t request video until playVideo() called. ```typescript import { YoutubePlayer } from '@capgo/capacitor-youtube-player'; await YoutubePlayer.cueVideoById({} as VideoByIdMethodOptions); ``` ### `loadVideoByUrl` [Section titled “loadVideoByUrl”](#loadvideobyurl) Load and play a video by its full URL. ```typescript import { YoutubePlayer } from '@capgo/capacitor-youtube-player'; await YoutubePlayer.loadVideoByUrl({} as VideoByUrlMethodOptions); ``` ### `cueVideoByUrl` [Section titled “cueVideoByUrl”](#cuevideobyurl) Cue a video by URL without playing it. ```typescript import { YoutubePlayer } from '@capgo/capacitor-youtube-player'; await YoutubePlayer.cueVideoByUrl({} as VideoByUrlMethodOptions); ``` ### `cuePlaylist` [Section titled “cuePlaylist”](#cueplaylist) Cue a playlist without playing it. Loads playlist and prepares first video. ```typescript import { YoutubePlayer } from '@capgo/capacitor-youtube-player'; await YoutubePlayer.cuePlaylist({} as PlaylistMethodOptions); ``` ### `loadPlaylist` [Section titled “loadPlaylist”](#loadplaylist) Load and play a playlist. ```typescript import { YoutubePlayer } from '@capgo/capacitor-youtube-player'; await YoutubePlayer.loadPlaylist({} as PlaylistMethodOptions); ``` ### `nextVideo` [Section titled “nextVideo”](#nextvideo) Play the next video in the playlist. ```typescript import { YoutubePlayer } from '@capgo/capacitor-youtube-player'; await YoutubePlayer.nextVideo({} as PlayerIdOptions); ``` ### `previousVideo` [Section titled “previousVideo”](#previousvideo) Play the previous video in the playlist. ```typescript import { YoutubePlayer } from '@capgo/capacitor-youtube-player'; await YoutubePlayer.previousVideo({} as PlayerIdOptions); ``` ### `playVideoAt` [Section titled “playVideoAt”](#playvideoat) Play a specific video in the playlist by index. ```typescript import { YoutubePlayer } from '@capgo/capacitor-youtube-player'; await YoutubePlayer.playVideoAt({} as PlayVideoAtOptions); ``` ### `mute` [Section titled “mute”](#mute) Mute the player audio. ```typescript import { YoutubePlayer } from '@capgo/capacitor-youtube-player'; await YoutubePlayer.mute({} as PlayerIdOptions); ``` ### `unMute` [Section titled “unMute”](#unmute) Unmute the player audio. ```typescript import { YoutubePlayer } from '@capgo/capacitor-youtube-player'; await YoutubePlayer.unMute({} as PlayerIdOptions); ``` ### `isMuted` [Section titled “isMuted”](#ismuted) Check if the player is currently muted. ```typescript import { YoutubePlayer } from '@capgo/capacitor-youtube-player'; await YoutubePlayer.isMuted({} as PlayerIdOptions); ``` ### `setVolume` [Section titled “setVolume”](#setvolume) Set the player volume level. ```typescript import { YoutubePlayer } from '@capgo/capacitor-youtube-player'; await YoutubePlayer.setVolume({} as SetVolumeOptions); ``` ### `getVolume` [Section titled “getVolume”](#getvolume) Get the current player volume level. Returns volume even if player is muted. ```typescript import { YoutubePlayer } from '@capgo/capacitor-youtube-player'; await YoutubePlayer.getVolume({} as PlayerIdOptions); ``` ### `setSize` [Section titled “setSize”](#setsize) Set the player dimensions in pixels. ```typescript import { YoutubePlayer } from '@capgo/capacitor-youtube-player'; await YoutubePlayer.setSize({} as SetSizeOptions); ``` ### `getPlaybackRate` [Section titled “getPlaybackRate”](#getplaybackrate) Get the current playback rate. ```typescript import { YoutubePlayer } from '@capgo/capacitor-youtube-player'; await YoutubePlayer.getPlaybackRate({} as PlayerIdOptions); ``` ### `setPlaybackRate` [Section titled “setPlaybackRate”](#setplaybackrate) Set the playback speed. ```typescript import { YoutubePlayer } from '@capgo/capacitor-youtube-player'; await YoutubePlayer.setPlaybackRate({} as SetPlaybackRateOptions); ``` ### `getAvailablePlaybackRates` [Section titled “getAvailablePlaybackRates”](#getavailableplaybackrates) Get list of available playback rates for current video. ```typescript import { YoutubePlayer } from '@capgo/capacitor-youtube-player'; await YoutubePlayer.getAvailablePlaybackRates({} as PlayerIdOptions); ``` ### `setLoop` [Section titled “setLoop”](#setloop) Enable or disable playlist looping. When enabled, playlist will restart from beginning after last video. ```typescript import { YoutubePlayer } from '@capgo/capacitor-youtube-player'; await YoutubePlayer.setLoop({} as SetLoopOptions); ``` ### `setShuffle` [Section titled “setShuffle”](#setshuffle) Enable or disable playlist shuffle. ```typescript import { YoutubePlayer } from '@capgo/capacitor-youtube-player'; await YoutubePlayer.setShuffle({} as SetShuffleOptions); ``` ### `getVideoLoadedFraction` [Section titled “getVideoLoadedFraction”](#getvideoloadedfraction) Get the fraction of the video that has been buffered. More reliable than deprecated getVideoBytesLoaded/getVideoBytesTotal. ```typescript import { YoutubePlayer } from '@capgo/capacitor-youtube-player'; await YoutubePlayer.getVideoLoadedFraction({} as PlayerIdOptions); ``` ### `getPlayerState` [Section titled “getPlayerState”](#getplayerstate) Get the current state of the player. ```typescript import { YoutubePlayer } from '@capgo/capacitor-youtube-player'; await YoutubePlayer.getPlayerState({} as PlayerIdOptions); ``` ### `getAllPlayersEventsState` [Section titled “getAllPlayersEventsState”](#getallplayerseventsstate) Get event states for all active players. Useful for tracking multiple player instances. ```typescript import { YoutubePlayer } from '@capgo/capacitor-youtube-player'; await YoutubePlayer.getAllPlayersEventsState(); ``` ### `getCurrentTime` [Section titled “getCurrentTime”](#getcurrenttime) Get the current playback position in seconds. ```typescript import { YoutubePlayer } from '@capgo/capacitor-youtube-player'; await YoutubePlayer.getCurrentTime({} as PlayerIdOptions); ``` ### `toggleFullScreen` [Section titled “toggleFullScreen”](#togglefullscreen) Toggle fullscreen mode on or off. ```typescript import { YoutubePlayer } from '@capgo/capacitor-youtube-player'; await YoutubePlayer.toggleFullScreen({} as ToggleFullScreenOptions); ``` ### `getPlaybackQuality` [Section titled “getPlaybackQuality”](#getplaybackquality) Get the current playback quality. ```typescript import { YoutubePlayer } from '@capgo/capacitor-youtube-player'; await YoutubePlayer.getPlaybackQuality({} as PlayerIdOptions); ``` ### `setPlaybackQuality` [Section titled “setPlaybackQuality”](#setplaybackquality) Set the suggested playback quality. Actual quality may differ based on network conditions. ```typescript import { YoutubePlayer } from '@capgo/capacitor-youtube-player'; await YoutubePlayer.setPlaybackQuality({} as SetPlaybackQualityOptions); ``` ### `getAvailableQualityLevels` [Section titled “getAvailableQualityLevels”](#getavailablequalitylevels) Get list of available quality levels for current video. ```typescript import { YoutubePlayer } from '@capgo/capacitor-youtube-player'; await YoutubePlayer.getAvailableQualityLevels({} as PlayerIdOptions); ``` ### `getDuration` [Section titled “getDuration”](#getduration) Get the duration of the current video in seconds. ```typescript import { YoutubePlayer } from '@capgo/capacitor-youtube-player'; await YoutubePlayer.getDuration({} as PlayerIdOptions); ``` ### `getVideoUrl` [Section titled “getVideoUrl”](#getvideourl) Get the YouTube.com URL for the current video. ```typescript import { YoutubePlayer } from '@capgo/capacitor-youtube-player'; await YoutubePlayer.getVideoUrl({} as PlayerIdOptions); ``` ### `getVideoEmbedCode` [Section titled “getVideoEmbedCode”](#getvideoembedcode) Get the embed code for the current video. Returns HTML iframe embed code. ```typescript import { YoutubePlayer } from '@capgo/capacitor-youtube-player'; await YoutubePlayer.getVideoEmbedCode({} as PlayerIdOptions); ``` ### `getPlaylist` [Section titled “getPlaylist”](#getplaylist) Get array of video IDs in the current playlist. ```typescript import { YoutubePlayer } from '@capgo/capacitor-youtube-player'; await YoutubePlayer.getPlaylist({} as PlayerIdOptions); ``` ### `getPlaylistIndex` [Section titled “getPlaylistIndex”](#getplaylistindex) Get the index of the currently playing video in the playlist. ```typescript import { YoutubePlayer } from '@capgo/capacitor-youtube-player'; await YoutubePlayer.getPlaylistIndex({} as PlayerIdOptions); ``` ### `getIframe` [Section titled “getIframe”](#getiframe) Get the iframe DOM element for the player. Web platform only. ```typescript import { YoutubePlayer } from '@capgo/capacitor-youtube-player'; await YoutubePlayer.getIframe({} as PlayerIdOptions); ``` ### `addEventListener` [Section titled “addEventListener”](#addeventlistener) Add an event listener to the player. Web platform only. ```typescript import { YoutubePlayer } from '@capgo/capacitor-youtube-player'; YoutubePlayer.addEventListener({ playerId: 'my-player', eventName: 'onStateChange', listener: (event) => { console.log('Player state:', event.data); }, }); ``` ### `removeEventListener` [Section titled “removeEventListener”](#removeeventlistener) Remove an event listener from the player. Web platform only. ```typescript import { YoutubePlayer } from '@capgo/capacitor-youtube-player'; await YoutubePlayer.removeEventListener({} as PlayerEventListenerOptions<TEvent>); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `PlayerIdOptions` [Section titled “PlayerIdOptions”](#playeridoptions) ```typescript export interface PlayerIdOptions { playerId: string; } ``` ### `SeekToOptions` [Section titled “SeekToOptions”](#seektooptions) ```typescript export interface SeekToOptions extends PlayerIdOptions { playerId: string; seconds: number; allowSeekAhead: boolean; } ``` ### `VideoByIdMethodOptions` [Section titled “VideoByIdMethodOptions”](#videobyidmethodoptions) ```typescript export interface VideoByIdMethodOptions extends PlayerIdOptions { playerId: string; options: IVideoOptionsById; } ``` ### `VideoByUrlMethodOptions` [Section titled “VideoByUrlMethodOptions”](#videobyurlmethodoptions) ```typescript export interface VideoByUrlMethodOptions extends PlayerIdOptions { playerId: string; options: IVideoOptionsByUrl; } ``` ### `PlaylistMethodOptions` [Section titled “PlaylistMethodOptions”](#playlistmethodoptions) ```typescript export interface PlaylistMethodOptions extends PlayerIdOptions { playerId: string; playlistOptions: IPlaylistOptions; } ``` ### `PlayVideoAtOptions` [Section titled “PlayVideoAtOptions”](#playvideoatoptions) ```typescript export interface PlayVideoAtOptions extends PlayerIdOptions { playerId: string; index: number; } ``` ### `SetVolumeOptions` [Section titled “SetVolumeOptions”](#setvolumeoptions) ```typescript export interface SetVolumeOptions extends PlayerIdOptions { playerId: string; volume: number; } ``` ### `SetSizeOptions` [Section titled “SetSizeOptions”](#setsizeoptions) ```typescript export interface SetSizeOptions extends PlayerIdOptions { playerId: string; width: number; height: number; } ``` ### `SetPlaybackRateOptions` [Section titled “SetPlaybackRateOptions”](#setplaybackrateoptions) ```typescript export interface SetPlaybackRateOptions extends PlayerIdOptions { playerId: string; suggestedRate: number; } ``` ### `SetLoopOptions` [Section titled “SetLoopOptions”](#setloopoptions) ```typescript export interface SetLoopOptions extends PlayerIdOptions { playerId: string; loopPlaylists: boolean; } ``` ### `SetShuffleOptions` [Section titled “SetShuffleOptions”](#setshuffleoptions) ```typescript export interface SetShuffleOptions extends PlayerIdOptions { playerId: string; shufflePlaylist: boolean; } ``` ### `ToggleFullScreenOptions` [Section titled “ToggleFullScreenOptions”](#togglefullscreenoptions) ```typescript export interface ToggleFullScreenOptions extends PlayerIdOptions { playerId: string; isFullScreen: boolean | null | undefined; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # @capgo/capacitor-zebra-datawedge > Capacitor plugin for Zebra DataWedge profile management, notifications, queries, and soft scanning on Zebra Android devices. ## Overview [Section titled “Overview”](#overview) Capacitor plugin for Zebra DataWedge profile management, notifications, queries, and soft scanning on Zebra Android devices. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `cloneProfile` * `createProfile` * `deleteProfile` * `importConfig` ## Public API [Section titled “Public API”](#public-api) | Method | Description | | --------------------------- | ------------------------------------------------ | | `cloneProfile` | See the source definitions for current behavior. | | `createProfile` | See the source definitions for current behavior. | | `deleteProfile` | See the source definitions for current behavior. | | `importConfig` | See the source definitions for current behavior. | | `renameProfile` | See the source definitions for current behavior. | | `restoreConfig` | See the source definitions for current behavior. | | `setConfig` | See the source definitions for current behavior. | | `setDisabledAppList` | See the source definitions for current behavior. | | `setIgnoreDisabledProfiles` | See the source definitions for current behavior. | | `registerForNotification` | See the source definitions for current behavior. | | `unRegisterForNotification` | See the source definitions for current behavior. | | `enumerateScanners` | See the source definitions for current behavior. | | `getActiveProfile` | See the source definitions for current behavior. | | `getAssociatedApps` | See the source definitions for current behavior. | | `getConfig` | See the source definitions for current behavior. | | `getDatawedgeStatus` | See the source definitions for current behavior. | | `getDisabledAppList` | See the source definitions for current behavior. | | `getIgnoreDisabledProfiles` | See the source definitions for current behavior. | | `getProfilesList` | See the source definitions for current behavior. | | `getScannerStatus` | See the source definitions for current behavior. | | `getVersionInfo` | See the source definitions for current behavior. | | `disableDatawedge` | See the source definitions for current behavior. | | `disableScannerInput` | See the source definitions for current behavior. | | `enableDatawedge` | See the source definitions for current behavior. | | `enableScannerInput` | See the source definitions for current behavior. | | `enumerateTriggers` | See the source definitions for current behavior. | | `notify` | See the source definitions for current behavior. | | `resetDefaultProfile` | See the source definitions for current behavior. | | `setDefaultProfile` | See the source definitions for current behavior. | | `setReportingOptions` | See the source definitions for current behavior. | | `softRfidTrigger` | See the source definitions for current behavior. | | `softScanTrigger` | See the source definitions for current behavior. | | `switchScanner` | See the source definitions for current behavior. | | `switchScannerParams` | See the source definitions for current behavior. | | `switchToProfile` | See the source definitions for current behavior. | | `getPluginVersion` | See the source definitions for current behavior. | | `addListener` | See the source definitions for current behavior. | | `addListener` | See the source definitions for current behavior. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-zebra-datawedge](https://github.com/Cap-go/capacitor-zebra-datawedge/). # Android Behavior > Understand how the Zebra DataWedge plugin maps to broadcast intents and scan events on Zebra Android devices. ## Intent output is required [Section titled “Intent output is required”](#intent-output-is-required) The plugin listens for scan results through Android broadcasts. Your Zebra DataWedge profile must: * be associated with your app package * enable `Intent Output` * use `Broadcast Intent` delivery * send scans to the same action you pass into `softScanTrigger()` If those values do not match, the plugin can still manage profiles and query DataWedge state, but scan events will not reach your Capacitor app. ## Scan events [Section titled “Scan events”](#scan-events) Subscribe to the Capacitor `scan` listener to receive decoded data: ```typescript import { ZebraDataWedge } from '@capgo/capacitor-zebra-datawedge'; await ZebraDataWedge.addListener('scan', (event) => { console.log(event.data); console.log(event.labelType); console.log(event.source); }); ``` `softScanTrigger(intentAction)` waits for the next scan broadcast on the action you provide and resolves with that decoded payload. ## Notifications [Section titled “Notifications”](#notifications) Use `ZebraNotification.registerForNotification()` when you need native scanner status or profile switch updates: ```typescript import { DataWedgeNotificationType, ZebraNotification, } from '@capgo/capacitor-zebra-datawedge'; await ZebraNotification.registerForNotification({ notificationType: DataWedgeNotificationType.SCANNER_STATUS, callback: (event) => { console.log(event.scannerStatus); }, }); ``` ## Production notes [Section titled “Production notes”](#production-notes) * DataWedge commands require Zebra’s `com.symbol.datawedge` package to be present and enabled. * `softRfidTrigger()` uses the first registered scan intent action. Register one before relying on RFID reads. * Keep one canonical intent action per scanning flow. That reduces mismatches between the DataWedge profile and your app listeners. # Getting Started > Install and configure the Zebra DataWedge Capacitor plugin for Zebra Android devices. 1. **Install the plugin** ```sh bun add @capgo/capacitor-zebra-datawedge ``` 2. **Sync native platforms** ```sh bunx cap sync android ``` 3. **Configure DataWedge on the device** * Create or pick a Zebra DataWedge profile associated with your app package. * Enable `Intent Output`. * Set `Intent delivery` to `Broadcast Intent`. * Choose an action such as `app.capgo.zebra.SCAN`. 4. **Review Android behavior** * Read the [Android notes](/docs/plugins/zebra-datawedge/android/) before enabling soft triggers in production. ## Basic setup [Section titled “Basic setup”](#basic-setup) ```typescript import { DataWedgeConfigMode, DataWedgePlugin, ZebraConfiguration, ZebraDataWedge, ZebraRuntime, } from '@capgo/capacitor-zebra-datawedge'; const intentAction = 'app.capgo.zebra.SCAN'; await ZebraConfiguration.setConfig({ profileName: 'CapgoZebraProfile', profileEnabled: true, configMode: DataWedgeConfigMode.CREATE_IF_NOT_EXIST, appList: [ { packageName: 'com.example.app', activityList: ['*'], }, ], pluginConfigs: [ { pluginName: DataWedgePlugin.BARCODE, resetConfig: true, paramList: { scanner_selection: 'auto', scanner_input_enabled: 'true', }, }, { pluginName: DataWedgePlugin.INTENT, resetConfig: true, paramList: { intent_output_enabled: 'true', intent_action: intentAction, intent_delivery: 2, }, }, ], }); await ZebraDataWedge.addListener('scan', (result) => { console.log('Scanned', result.data, result.labelType); }); const result = await ZebraRuntime.softScanTrigger(intentAction); console.log(result.data); ``` ## Main runtime groups [Section titled “Main runtime groups”](#main-runtime-groups) * `ZebraConfiguration` manages profiles and disabled-app settings. * `ZebraNotification` registers for DataWedge notification broadcasts such as scanner status and profile switches. * `ZebraQuery` reads active profiles, associated apps, scanner status, scanner lists, and version info. * `ZebraRuntime` enables or disables DataWedge, switches scanners, and triggers scans. ## Platform scope [Section titled “Platform scope”](#platform-scope) * Android: fully supported on Zebra devices with DataWedge installed. * iOS: not available because DataWedge is Zebra Android specific. * Web: not available beyond API shape parity. # @capgo/capacitor-zip > Capacitor Zip Plugin for compressing and extracting zip archives. ## Overview [Section titled “Overview”](#overview) Capacitor Zip Plugin for compressing and extracting zip archives. ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * `zip` - Compress a file or directory to create a ZIP archive. * `unzip` - Extract a ZIP archive to a specified destination directory. ## Public API [Section titled “Public API”](#public-api) | Method | Description | | ------------------ | ----------------------------------------------------------- | | `zip` | Compress a file or directory to create a ZIP archive. | | `unzip` | Extract a ZIP archive to a specified destination directory. | | `getPluginVersion` | Get the native plugin version. | ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This reference is synced from `src/definitions.ts` in [capacitor-zip](https://github.com/Cap-go/capacitor-zip/). # Getting Started > Install @capgo/capacitor-zip and start using its current Capacitor API. ## Install [Section titled “Install”](#install) ```bash bun add @capgo/capacitor-zip bunx cap sync ``` ## Import [Section titled “Import”](#import) ```typescript import { CapacitorZip } from '@capgo/capacitor-zip'; ``` ## API Overview [Section titled “API Overview”](#api-overview) ### `zip` [Section titled “zip”](#zip) Compress a file or directory to create a ZIP archive. Creates a compressed archive from a source file or directory. The archive will include the entire directory structure if the source is a folder. Platform-specific notes: * iOS: Password protection is not supported. If a password is provided, it will be ignored and a warning will be logged. * Android: Supports AES-256 encryption when a password is provided. * Web: Not supported. Throws an error if called. ```typescript import { CapacitorZip } from '@capgo/capacitor-zip'; // Compress a directory without password await CapacitorZip.zip({ source: '/path/to/my-folder', destination: '/path/to/output.zip' }); ``` ### `unzip` [Section titled “unzip”](#unzip) Extract a ZIP archive to a specified destination directory. Extracts all files and folders from a ZIP archive while preserving the directory structure. Creates the destination directory if it doesn’t exist. Platform-specific notes: * iOS: Supports standard ZIP archives. Password-protected archives are extracted with the provided password. * Android: Supports AES-encrypted archives with password. Includes zip slip vulnerability protection. * Web: Downloads each file individually to the browser’s download folder. Cannot create a directory structure. ```typescript import { CapacitorZip } from '@capgo/capacitor-zip'; // Extract a standard ZIP archive await CapacitorZip.unzip({ source: '/path/to/archive.zip', destination: '/path/to/extract-folder' }); ``` ## Type Reference [Section titled “Type Reference”](#type-reference) ### `ZipOptions` [Section titled “ZipOptions”](#zipoptions) Options for creating a ZIP archive. ````typescript export interface ZipOptions { /** * Path to the file or directory to compress. * * This can be an absolute path or a path relative to the app's working directory. * If the source is a directory, all its contents will be recursively compressed * while preserving the directory structure. * * Platform-specific notes: * - iOS: Use file:// URLs or absolute paths. Relative paths are resolved from the app's documents directory. * - Android: Use absolute file paths or content:// URIs for files accessible via the Android Storage Access Framework. * - Web: Not supported. * * @since 7.0.0 * @example '/Users/app/Documents/my-folder' * @example '/var/mobile/Containers/Data/Application/.../Documents/file.pdf' * @example 'file:///storage/emulated/0/Download/document.pdf' */ source: string; /** * Path where the ZIP archive will be created. * * The destination path must include the .zip file extension. If the parent * directory doesn't exist, it will be created automatically. * * Platform-specific notes: * - iOS: Use file:// URLs or absolute paths. Relative paths are resolved from the app's documents directory. * - Android: Use absolute file paths. The plugin will create any missing parent directories. * - Web: Not supported. * * @since 7.0.0 * @example '/Users/app/Documents/archive.zip' * @example '/var/mobile/Containers/Data/Application/.../Documents/backup.zip' * @example 'file:///storage/emulated/0/Download/compressed.zip' */ destination: string; /** * Optional password for encrypting the ZIP archive. * * When provided, the archive will be encrypted and require this password * to extract. Uses AES-256 encryption on Android. * * Platform-specific notes: * - iOS: Password protection is NOT supported. The password will be ignored and a warning will be logged. * - Android: Supports AES-256 encryption via zip4j library. The password must be provided during extraction. * - Web: Not supported. * * @since 7.0.0 * @example 'mySecurePassword123' */ password?: string; /** * Whether to include the parent folder in the ZIP archive. * * When true (default), the source folder itself becomes the root directory in the archive. * When false, only the contents of the source folder are included at the root level. * * This option only applies when the source is a directory. For single files, this option is ignored. * * @default true * @since 8.0.5 * @example * ```typescript * // With includeParentFolder: true (default) * // Source: /cache/temp/ containing [database.backup, media/] * // ZIP contains: temp/database.backup, temp/media/ * await CapacitorZip.zip({ * source: '/cache/temp', * destination: '/cache/backup.zip', * includeParentFolder: true * }); * ``` * @example * ```typescript * // With includeParentFolder: false * // Source: /cache/temp/ containing [database.backup, media/] * // ZIP contains: database.backup, media/ * await CapacitorZip.zip({ * source: '/cache/temp', * destination: '/cache/backup.zip', * includeParentFolder: false * }); * ``` */ includeParentFolder?: boolean; } ```` ### `UnzipOptions` [Section titled “UnzipOptions”](#unzipoptions) Options for extracting a ZIP archive. ```typescript export interface UnzipOptions { /** * Path to the ZIP archive to extract. * * The source must be a valid ZIP file. If the file doesn't exist or is * corrupted, the operation will fail with an error. * * Platform-specific notes: * - iOS: Use file:// URLs or absolute paths. Relative paths are resolved from the app's documents directory. * - Android: Use absolute file paths or content:// URIs for files accessible via the Android Storage Access Framework. * - Web: Use HTTP/HTTPS URLs. The file will be fetched and extracted in the browser. * * @since 7.0.0 * @example '/Users/app/Documents/archive.zip' * @example '/var/mobile/Containers/Data/Application/.../Documents/backup.zip' * @example 'file:///storage/emulated/0/Download/compressed.zip' * @example 'https://example.com/files/archive.zip' (Web only) */ source: string; /** * Path to the directory where files will be extracted. * * The destination directory will be created if it doesn't exist. All files * and folders from the archive will be extracted while preserving the * directory structure. * * Platform-specific notes: * - iOS: Use file:// URLs or absolute paths. Relative paths are resolved from the app's documents directory. * - Android: Use absolute file paths. Includes protection against zip slip vulnerabilities. * - Web: Not applicable. Files are downloaded individually to the browser's download folder. * * @since 7.0.0 * @example '/Users/app/Documents/extracted' * @example '/var/mobile/Containers/Data/Application/.../Documents/files' * @example 'file:///storage/emulated/0/Download/extracted-files' */ destination: string; /** * Optional password for decrypting password-protected archives. * * Required if the ZIP archive was encrypted with a password. If the password * is incorrect, extraction will fail with an error. * * Platform-specific notes: * - iOS: Supports password-protected ZIP archives. * - Android: Supports AES-encrypted archives created with zip4j or standard password-protected ZIPs. * - Web: Not supported. Password-protected archives cannot be extracted in the browser. * * @since 7.0.0 * @example 'mySecurePassword123' */ password?: string; } ``` ## Source Of Truth [Section titled “Source Of Truth”](#source-of-truth) This page is generated from the plugin’s `src/definitions.ts`. Re-run the sync when the public API changes upstream. # API Overview > Explore Capgo's public API for managing resources such as organizations, devices, channels, and bundles using RESTful HTTP methods and authentication. This is the documentation of the public API of Capgo cloud. The API allows you to programmatically manage your Capgo resources, including organizations, devices, channels, and bundles. It’s designed to be RESTful and uses standard HTTP methods. ## Authentication [Section titled “Authentication”](#authentication) All API endpoints require authentication. To authenticate your requests, add your API key in the `authorization` header. Example: ```bash curl -H "authorization: your-api-key" https://api.capgo.app/organization/ ``` [Get API key ](https://console.capgo.app/dashboard/apikeys/)Generate your API key in the Capgo dashboard ## Rate Limiting [Section titled “Rate Limiting”](#rate-limiting) The API implements rate limiting to ensure fair usage. Current limits are: * 100 requests per minute for standard accounts * 1000 requests per minute for enterprise accounts If you exceed these limits, you’ll receive a 429 (Too Many Requests) response. ## Response Format [Section titled “Response Format”](#response-format) All responses are in JSON format. Successful responses typically include either a `data` object or a `status` field. Error responses include an `error` field with a description of what went wrong. Example success response: ```json { "status": "ok", "data": { ... } } ``` Example error response: ```json { "error": "Invalid API key", "status": "KO" } ``` ## Available Endpoints [Section titled “Available Endpoints”](#available-endpoints) [Organizations ](/docs/public-api/organizations/)Create and manage organizations, update settings, and handle organization-level configurations [API Keys ](/docs/public-api/api-keys/)Generate, list, and revoke API keys for secure access to the Capgo API [Members ](/docs/public-api/members/)Manage organization members, roles, and permissions [Statistics ](/docs/public-api/statistics/)Access detailed analytics about app usage, storage, and bandwidth consumption [Channels ](/docs/public-api/channels/)Control app update channels, bundles (versions), and update policies [Devices ](/docs/public-api/devices/)Track and manage devices running your app, including bundle (version) and channel assignments [Bundles ](/docs/public-api/bundles/)Handle app bundles, including uploading, listing, and managing bundles (versions) ## Best Practices [Section titled “Best Practices”](#best-practices) 1. **Error Handling**: Always check for error responses and handle them appropriately 2. **Rate Limiting**: Implement exponential backoff when hitting rate limits 3. **Caching**: Cache responses when appropriate to reduce API calls 4. **Versioning**: Keep track of API changes through our changelog # API Keys > Comprehensive documentation for API Keys, detailing authentication, RBAC permissions, and management within Capgo API keys are used to authenticate requests to the Capgo API. Keys are organization-specific and can be assigned RBAC roles for fine-grained access control. Each key can also have an optional expiration date and can be created as a “secure” (hashed) key where the plain-text value is only shown once. ## Using an API key [Section titled “Using an API key”](#using-an-api-key) Pass your API key in the `x-api-key` header of every request: ```bash curl -H "x-api-key: YOUR_API_KEY" https://api.capgo.app/... ``` The `authorization` header is also accepted but is primarily intended for JWT tokens. When the value is a UUID-formatted API key it works, but `x-api-key` is the recommended header for all key types (including secure/hashed keys). ## RBAC Permissions [Section titled “RBAC Permissions”](#rbac-permissions) API keys use the same role-based access control (RBAC) system as user accounts. When creating or managing keys through the web app, you assign roles at two levels: * **Organization role** — Defines the key’s baseline permissions across the entire organization (e.g. `org_admin`, `org_member`). * **App roles** — Optional per-app permissions (e.g. `app_admin`, `app_developer`, `app_uploader`, `app_reader`). If an API key has explicit role bindings, **only those bindings** are evaluated for permission checks. The key owner’s personal permissions are not inherited by the key. ![A diagram explaining how RBAC API key permissions work](/capgo_apikeys_rbac_diagram.webp) Note Keys without role bindings fall back to a legacy mode-based system (`read`, `upload`, `write`, `all`). These modes are deprecated — use RBAC roles instead. ## Secure (Hashed) Keys [Section titled “Secure (Hashed) Keys”](#secure-hashed-keys) When creating a secure key, the server generates the key material and returns the plain-text value once. Only a hash is stored. This means: * The plain-text key **cannot be retrieved** after creation. * Regeneration produces a new plain-text key (shown once) and updates the stored hash. * Hashed keys are recommended for production use. Some organizations enforce hashed keys via the `enforce_hashed_api_keys` org policy. ## Expiration [Section titled “Expiration”](#expiration) Keys can have an optional expiration date. Expired keys are rejected at the permission check layer. Organization policies can enforce: * **Mandatory expiration** (`require_apikey_expiration`) — All new keys must have an expiry. * **Maximum TTL** (`max_apikey_expiration_days`) — The expiry cannot be further than N days from now. ## Security Best Practices [Section titled “Security Best Practices”](#security-best-practices) 1. **Principle of Least Privilege**: Assign the most restrictive role that still allows your integration to function 2. **Regular Rotation**: Rotate your API keys periodically using the regenerate feature 3. **Secure Storage**: Store API keys securely and never commit them to version control 4. **Use Hashed Keys**: Create secure (hashed) keys for production integrations 5. **Set Expiration**: Always set an expiration date on keys used for temporary or CI/CD access 6. **Scope Restrictions**: Restrict keys to specific apps with the minimum required role ## Common Use Cases [Section titled “Common Use Cases”](#common-use-cases) 1. **CI/CD Integration**: Create keys scoped to specific apps with the `app_uploader` or `app_developer` role, and set an expiration date 2. **Deployment Automation**: Use keys with the `app_developer` role for automated deployment scripts 3. **Monitoring Tools**: Create keys with the `app_reader` role for external monitoring integrations 4. **Admin Access**: Use keys with the `org_admin` role sparingly for administrative tools 5. **Third-Party Integrations**: Create keys restricted to specific apps with the minimum required role # Apps > Detailed documentation for the Apps endpoint, providing comprehensive insights into managing and interacting with Capacitor applications through Capgo's platform. Apps are the foundational entities in Capgo. Each app represents a unique Capacitor application that you can manage and update through the platform. The Apps API allows you to create, retrieve, update, and delete app configurations. ## Understanding Apps [Section titled “Understanding Apps”](#understanding-apps) An app in Capgo represents your Capacitor application and includes: * **App ID**: Unique identifier for your application * **Name**: Human-readable name of your application * **Icons**: Visual identifiers for your app in the dashboard * **Configuration**: Settings that control how updates are delivered * **Ownership**: Organization and user access information * **Usage Statistics**: Metrics about installs and updates ## Best Practices [Section titled “Best Practices”](#best-practices) 1. **Naming Convention**: Use clear, identifiable names for your apps 2. **Security**: Protect your API keys and access credentials 3. **Organization**: Group related apps under the same organization 4. **Monitoring**: Regularly check app statistics and performance 5. **Backup**: Maintain configuration backups for critical apps ## Endpoints [Section titled “Endpoints”](#endpoints) ### GET [Section titled “GET”](#get) `https://api.capgo.app/app/` Retrieve information about your apps. #### Query Parameters [Section titled “Query Parameters”](#query-parameters) * `page`: Optional. Page number for pagination * `limit`: Optional. Number of results per page (default: 50) * `org_id`: Optional. Filter apps by organization ID. If not provided, returns apps from all organizations the user has access to For getting a specific app: * Use the app ID in the URL path: `https://api.capgo.app/app/:app_id` #### Response Type [Section titled “Response Type”](#response-type) Note: `last_version` refers to the last bundle (version) uploaded for the app. ```typescript interface App { app_id: string created_at: string | null default_upload_channel: string icon_url: string id: string | null last_version: string | null // last bundle (version) name name: string | null owner_org: string retention: number transfer_history: Json[] | null updated_at: string | null user_id: string | null } ``` #### Example Request [Section titled “Example Request”](#example-request) ```bash # Get all apps curl -H "authorization: your-api-key" \ "https://api.capgo.app/app/" # Get apps from a specific organization curl -H "authorization: your-api-key" \ "https://api.capgo.app/app/?org_id=046a36ac-e03c-4590-9257-bd6c9dba9ee8" # Get specific app curl -H "authorization: your-api-key" \ "https://api.capgo.app/app/com.demo.app" ``` #### Example Response [Section titled “Example Response”](#example-response) ```json { "data": [ { "app_id": "com.demo.app", "created_at": "2024-01-01T00:00:00Z", "default_upload_channel": "dev", "icon_url": "https://example.com/icon.png", "id": "550e8400-e29b-41d4-a716-446655440000", "last_version": "1.0.0", "name": "Demo App", "owner_org": "046a36ac-e03c-4590-9257-bd6c9dba9ee8", "retention": 2592000, "transfer_history": null, "updated_at": "2024-01-01T00:00:00Z", "user_id": "6aa76066-55ef-4238-ade6-0b32334a4097" } ] } ``` ### POST [Section titled “POST”](#post) `https://api.capgo.app/app/` Create a new app. #### Request Body [Section titled “Request Body”](#request-body) ```typescript interface CreateApp { app_id: string name: string icon?: string owner_org: string } ``` #### Example Request [Section titled “Example Request”](#example-request-1) ```bash # Create new app curl -X POST \ -H "authorization: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "name": "My New App", "app_id": "com.demo.myapp", // this id is unique in Capgo This cannot be reused by any account. "icon": "https://example.com/icon.png", "owner_org": "046a36ac-e03c-4590-9257-bd6c9dba9ee8" }' \ https://api.capgo.app/app/ ``` #### Success Response [Section titled “Success Response”](#success-response) ```json { "app_id": "My New App", "created_at": "2024-01-01T00:00:00Z", "default_upload_channel": "dev", "icon_url": "https://example.com/icon.png", "id": "550e8400-e29b-41d4-a716-446655440000", "name": "My New App", "owner_org": "046a36ac-e03c-4590-9257-bd6c9dba9ee8", "retention": 2592000, "updated_at": "2024-01-01T00:00:00Z" } ``` ### PUT [Section titled “PUT”](#put) `https://api.capgo.app/app/:app_id` Update an existing app. The app ID is specified in the URL path. #### Request Body [Section titled “Request Body”](#request-body-1) ```typescript interface UpdateApp { name?: string icon?: string retention?: number } ``` #### Example Request [Section titled “Example Request”](#example-request-2) ```bash curl -X PUT \ -H "authorization: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "name": "Updated App Name", "icon": "https://example.com/updated-icon.png", "retention": 45 }' \ https://api.capgo.app/app/com.demo.app ``` #### Success Response [Section titled “Success Response”](#success-response-1) ```json { "app_id": "com.demo.app", "created_at": "2024-01-01T00:00:00Z", "default_upload_channel": "dev", "icon_url": "https://example.com/updated-icon.png", "id": "550e8400-e29b-41d4-a716-446655440000", "name": "Updated App Name", "owner_org": "046a36ac-e03c-4590-9257-bd6c9dba9ee8", "retention": 45, "updated_at": "2024-01-01T00:00:00Z" } ``` ### DELETE [Section titled “DELETE”](#delete) `https://api.capgo.app/app/:app_id` Delete an app and all associated resources. The app ID is specified in the URL path. Use with extreme caution as this action cannot be undone. #### Example Request [Section titled “Example Request”](#example-request-3) ```bash curl -X DELETE \ -H "authorization: your-api-key" \ https://api.capgo.app/app/com.demo.app ``` #### Success Response [Section titled “Success Response”](#success-response-2) ```json { "status": "ok" } ``` ## Error Handling [Section titled “Error Handling”](#error-handling) Common error scenarios and their responses: ```json // App not found { "error": "App not found", "status": "KO" } // Duplicate custom ID { "error": "Custom ID already in use", "status": "KO" } // Invalid parameters { "error": "Invalid app configuration", "status": "KO" } // Permission denied { "error": "Insufficient permissions to manage app", "status": "KO" } // Organization access denied { "status": "You do not have access to this organization" } ``` ## Common Use Cases [Section titled “Common Use Cases”](#common-use-cases) 1. **Create New App** ```typescript // Set up a new app { "name": "Production App", "owner_org": "046a36ac-e03c-4590-9257-bd6c9dba9ee8" } ``` 2. **Update App Configuration** ```typescript // Change app name and icon { "name": "Rebranded App Name", "icon": "https://example.com/new-icon.png" } ``` 3. **Set Retention Policy** ```typescript // Configure automatic bundle cleanup { "retention": 30 // Keep bundles for 30 days } ``` 4. **Get Apps by Organization** ```bash # List all apps in a specific organization curl -H "authorization: your-api-key" \ "https://api.capgo.app/app/?org_id=046a36ac-e03c-4590-9257-bd6c9dba9ee8" ``` ## Resource Management [Section titled “Resource Management”](#resource-management) 1. **Storage Optimization**: Monitor storage usage and set appropriate retention policies 2. **Organization**: Group related apps under a single organization 3. **Access Control**: Manage which team members can modify app settings 4. **Backup Strategy**: Back up critical app configurations and settings # Bundles > Detailed guide for managing Capgo Bundles, covering listing, deleting, bundle (version) management, and storage optimization for app update packages. Bundles are the core update packages in Capgo. Each bundle contains the web assets (HTML, CSS, JS) that make up your app’s content. The Bundles API allows you to manage these update packages, including listing and deleting them. ## Understanding Bundles [Section titled “Understanding Bundles”](#understanding-bundles) A bundle represents a specific bundle (version) of your app’s web content and includes: * **Bundle (version)**: Semantic version number for the bundle * **Checksum**: Unique hash to verify bundle integrity * **Storage Info**: Details about where and how the bundle is stored * **Native Requirements**: Minimum native app version requirements * **Metadata**: Creation time, ownership, and other tracking information ## Manual Bundle Creation (Without CLI) [Section titled “Manual Bundle Creation (Without CLI)”](#manual-bundle-creation-without-cli) Here’s how to create and upload bundles manually without using the Capgo CLI: ### Step 1: Build Your App [Section titled “Step 1: Build Your App”](#step-1-build-your-app) First, build your app’s web assets: ```bash npm run build ``` ### Step 2: Create Bundle Zip Using Same Packages as Capgo CLI [Section titled “Step 2: Create Bundle Zip Using Same Packages as Capgo CLI”](#step-2-create-bundle-zip-using-same-packages-as-capgo-cli) **Important**: Use the exact same JavaScript packages that Capgo CLI uses internally to ensure compatibility. #### Install Required Packages [Section titled “Install Required Packages”](#install-required-packages) ```bash npm install adm-zip @tomasklaen/checksum ``` #### Create Zip Bundle with JavaScript (Same as Capgo CLI) [Section titled “Create Zip Bundle with JavaScript (Same as Capgo CLI)”](#create-zip-bundle-with-javascript-same-as-capgo-cli) Note: In the examples below, `version` refers to the bundle (version) name used by the API. ```javascript const fs = require('node:fs'); const path = require('node:path'); const os = require('node:os'); const AdmZip = require('adm-zip'); const { checksum: getChecksum } = require('@tomasklaen/checksum'); // Exact same implementation as Capgo CLI function zipFileUnix(filePath) { const zip = new AdmZip(); zip.addLocalFolder(filePath); return zip.toBuffer(); } async function zipFileWindows(filePath) { console.log('Zipping file windows mode'); const zip = new AdmZip(); const addToZip = (folderPath, zipPath) => { const items = fs.readdirSync(folderPath); for (const item of items) { const itemPath = path.join(folderPath, item); const stats = fs.statSync(itemPath); if (stats.isFile()) { const fileContent = fs.readFileSync(itemPath); zip.addFile(path.join(zipPath, item).split(path.sep).join('/'), fileContent); } else if (stats.isDirectory()) { addToZip(itemPath, path.join(zipPath, item)); } } }; addToZip(filePath, ''); return zip.toBuffer(); } // Main zipFile function (exact same logic as CLI) async function zipFile(filePath) { if (os.platform() === 'win32') { return zipFileWindows(filePath); } else { return zipFileUnix(filePath); } } async function createBundle(inputPath, outputPath, version) { // Create zip using exact same method as Capgo CLI const zipped = await zipFile(inputPath); // Write to file fs.writeFileSync(outputPath, zipped); // Calculate checksum using exact same package as CLI const checksum = await getChecksum(zipped, 'sha256'); return { filename: path.basename(outputPath), version: version, size: zipped.length, checksum: checksum }; } // Usage async function main() { try { const result = await createBundle('./dist', './my-app-1.2.3.zip', '1.2.3'); console.log('Bundle info:', JSON.stringify(result, null, 2)); } catch (error) { console.error('Error creating bundle:', error); } } main(); ``` ### Step 3: Calculate SHA256 Checksum Using Same Package as CLI [Section titled “Step 3: Calculate SHA256 Checksum Using Same Package as CLI”](#step-3-calculate-sha256-checksum-using-same-package-as-cli) ```javascript const fs = require('node:fs'); const { checksum: getChecksum } = require('@tomasklaen/checksum'); async function calculateChecksum(filePath) { const fileBuffer = fs.readFileSync(filePath); // Use exact same package and method as Capgo CLI const checksum = await getChecksum(fileBuffer, 'sha256'); return checksum; } // Usage async function main() { const checksum = await calculateChecksum('./my-app-1.2.3.zip'); console.log('Checksum:', checksum); } main(); ``` ### Step 4: Upload Bundle to Your Storage [Section titled “Step 4: Upload Bundle to Your Storage”](#step-4-upload-bundle-to-your-storage) Upload your zip file to any web-accessible storage: ```bash # Example: Upload to your server via scp scp my-app-1.2.3.zip user@your-server.com:/var/www/bundles/ # Example: Upload to S3 using AWS CLI aws s3 cp my-app-1.2.3.zip s3://your-bucket/bundles/ # Example: Upload via curl to a custom endpoint curl -X POST https://your-storage-api.com/upload \ -H "Authorization: Bearer YOUR_TOKEN" \ -F "file=@my-app-1.2.3.zip" ``` **Important**: Your bundle must be **publicly accessible** via HTTPS URL (no authentication required). Capgo’s servers need to download the bundle from this URL. Examples of valid public URLs: * `https://your-storage.com/bundles/my-app-1.2.3.zip` * `https://github.com/username/repo/releases/download/v1.2.3/bundle.zip` * `https://cdn.jsdelivr.net/gh/username/repo@v1.2.3/dist.zip` ### Step 5: Register Bundle with Capgo API [Section titled “Step 5: Register Bundle with Capgo API”](#step-5-register-bundle-with-capgo-api) Register the external bundle with Capgo using direct API calls: ```javascript async function registerWithCapgo(appId, version, bundleUrl, checksum, apiKey) { const fetch = require('node-fetch'); // Create bundle (version) const response = await fetch('https://api.capgo.app/bundle/', { method: 'POST', headers: { 'Content-Type': 'application/json', 'authorization': apiKey }, body: JSON.stringify({ app_id: appId, version: version, external_url: bundleUrl, checksum: checksum }) }); if (!response.ok) { throw new Error(`Failed to create bundle: ${response.statusText}`); } const data = await response.json(); console.log('Bundle created:', data); return data; } ``` #### API Parameters [Section titled “API Parameters”](#api-parameters) | Parameter | Description | Required | | -------------- | ----------------------------------------------------------------------------------- | -------- | | `app_id` | Your app identifier | Yes | | `version` | Bundle (version) semantic version (e.g., “1.2.3”) | Yes | | `external_url` | **Publicly accessible** HTTPS URL where bundle can be downloaded (no auth required) | Yes | | `checksum` | SHA256 checksum of the zip file | Yes | ## Bundle Structure Requirements [Section titled “Bundle Structure Requirements”](#bundle-structure-requirements) Your bundle zip must follow these requirements: 1. **Root Index File**: Must have `index.html` at the root level 2. **Capacitor Integration**: Must call `notifyAppReady()` in your app code 3. **Asset Paths**: Use relative paths for all assets ### Valid Bundle Structure [Section titled “Valid Bundle Structure”](#valid-bundle-structure) ```plaintext bundle.zip ├── index.html ├── assets/ │ ├── app.js │ └── styles.css └── images/ ``` ## Complete Manual Workflow Example [Section titled “Complete Manual Workflow Example”](#complete-manual-workflow-example) Simple Node.js script to zip, checksum, and upload to Capgo: ```javascript const fs = require('node:fs'); const os = require('node:os'); const AdmZip = require('adm-zip'); const { checksum: getChecksum } = require('@tomasklaen/checksum'); const fetch = require('node-fetch'); async function deployToCapgo() { const APP_ID = 'com.example.app'; const VERSION = '1.2.3'; const BUNDLE_URL = 'https://your-storage.com/bundles/app-1.2.3.zip'; const API_KEY = process.env.CAPGO_API_KEY; // 1. Create zip (same as Capgo CLI) const zip = new AdmZip(); zip.addLocalFolder('./dist'); const zipped = zip.toBuffer(); // 2. Calculate checksum (same as Capgo CLI) const checksum = await getChecksum(zipped, 'sha256'); console.log('Checksum:', checksum); // 3. Upload to your storage (replace with your upload logic) // fs.writeFileSync('./bundle.zip', zipped); // ... upload bundle.zip to your storage ... // 4. Register with Capgo API const response = await fetch('https://api.capgo.app/bundle/', { method: 'POST', headers: { 'Content-Type': 'application/json', 'authorization': API_KEY }, body: JSON.stringify({ app_id: APP_ID, version: VERSION, external_url: BUNDLE_URL, checksum: checksum }) }); if (!response.ok) { throw new Error(`Failed: ${response.statusText}`); } console.log('Bundle registered with Capgo!'); } deployToCapgo().catch(console.error); ``` Install dependencies: ```bash npm install adm-zip @tomasklaen/checksum node-fetch ``` ## Checksum Verification [Section titled “Checksum Verification”](#checksum-verification) ### JavaScript Checksum Calculation (Same as Capgo CLI) [Section titled “JavaScript Checksum Calculation (Same as Capgo CLI)”](#javascript-checksum-calculation-same-as-capgo-cli) Use the exact same package and method that Capgo CLI uses internally: ```javascript const fs = require('node:fs'); const { checksum: getChecksum } = require('@tomasklaen/checksum'); async function calculateChecksum(filePath) { const fileBuffer = fs.readFileSync(filePath); // Use exact same package and method as Capgo CLI const checksum = await getChecksum(fileBuffer, 'sha256'); return checksum; } // Verify checksum matches async function verifyChecksum(filePath, expectedChecksum) { const actualChecksum = await calculateChecksum(filePath); const isValid = actualChecksum === expectedChecksum; console.log(`File: ${filePath}`); console.log(`Expected: ${expectedChecksum}`); console.log(`Actual: ${actualChecksum}`); console.log(`Valid: ${isValid}`); return isValid; } // Usage async function main() { const bundleChecksum = await calculateChecksum('./my-app-1.2.3.zip'); console.log('SHA256 Checksum:', bundleChecksum); } main(); ``` ### Checksum Importance [Section titled “Checksum Importance”](#checksum-importance) * **Bundle Integrity**: Ensures the bundle hasn’t been corrupted during transfer * **API Verification**: Capgo verifies checksums before accepting bundles * **Plugin Verification**: The mobile plugin verifies checksums before applying updates ## Best Practices [Section titled “Best Practices”](#best-practices) 1. **Bundle (version) Management**: Use semantic versioning consistently 2. **Storage Optimization**: Remove unused bundles periodically 3. **Bundle (version) Compatibility**: Set appropriate minimum native version requirements 4. **Backup Strategy**: Maintain backups of critical bundles (versions) ## Endpoints [Section titled “Endpoints”](#endpoints) ### GET [Section titled “GET”](#get) `https://api.capgo.app/bundle/` Retrieve bundle information. Returns 50 bundles per page. #### Query Parameters [Section titled “Query Parameters”](#query-parameters) * `app_id`: Required. The ID of your app * `page`: Optional. Page number for pagination #### Response Type [Section titled “Response Type”](#response-type) ```typescript interface Bundle { app_id: string bucket_id: string | null checksum: string | null created_at: string | null deleted: boolean external_url: string | null id: number minUpdateVersion: string | null name: string native_packages: Json[] | null owner_org: string r2_path: string | null session_key: string | null storage_provider: string updated_at: string | null user_id: string | null } ``` #### Example Request [Section titled “Example Request”](#example-request) ```bash # Get all bundles curl -H "authorization: your-api-key" \ "https://api.capgo.app/bundle/?app_id=app_123" # Get next page curl -H "authorization: your-api-key" \ "https://api.capgo.app/bundle/?app_id=app_123&page=1" ``` #### Example Response [Section titled “Example Response”](#example-response) ```json { "data": [ { "id": 1, "app_id": "app_123", "name": "1.0.0", "checksum": "abc123...", "minUpdateVersion": "1.0.0", "storage_provider": "r2", "created_at": "2024-01-01T00:00:00Z", "updated_at": "2024-01-01T00:00:00Z", "deleted": false, "owner_org": "org_123", "user_id": "user_123" } ] } ``` ### DELETE [Section titled “DELETE”](#delete) `https://api.capgo.app/bundle/` Delete one or all bundles for an app. Use with caution as this action cannot be undone. #### Query Parameters [Section titled “Query Parameters”](#query-parameters-1) For deleting a specific bundle: ```typescript interface BundleDelete { app_id: string version: string } ``` For deleting all bundles: ```typescript interface BundleDeleteAll { app_id: string } ``` #### Example Requests [Section titled “Example Requests”](#example-requests) ```bash # Delete specific bundle curl -X DELETE \ -H "authorization: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "app_id": "app_123", "version": "1.0.0" }' \ https://api.capgo.app/bundle/ # Delete all bundles curl -X DELETE \ -H "authorization: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "app_id": "app_123" }' \ https://api.capgo.app/bundle/ ``` #### Success Response [Section titled “Success Response”](#success-response) ```json { "status": "ok" } ``` ### POST [Section titled “POST”](#post) `https://api.capgo.app/bundle/` Create a new bundle with external URL. #### Request Body [Section titled “Request Body”](#request-body) ```typescript interface CreateBundleBody { app_id: string version: string external_url: string // Must be publicly accessible HTTPS URL checksum: string } ``` #### Example Request [Section titled “Example Request”](#example-request-1) ```bash curl -X POST \ -H "authorization: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "app_id": "com.example.app", "version": "1.2.3", "external_url": "https://your-storage.com/bundles/app-1.2.3.zip", "checksum": "a1b2c3d4e5f6789abcdef123456789abcdef123456789abcdef123456789abcd" }' \ https://api.capgo.app/bundle/ ``` #### Success Response [Section titled “Success Response”](#success-response-1) ```json { "status": "ok" } ``` ### POST (Metadata) [Section titled “POST (Metadata)”](#post-metadata) `https://api.capgo.app/bundle/metadata` Update bundle metadata such as link and comment information. #### Request Body [Section titled “Request Body”](#request-body-1) ```typescript interface UpdateMetadataBody { app_id: string version_id: number // bundle (version) id link?: string comment?: string } ``` #### Example Request [Section titled “Example Request”](#example-request-2) ```bash curl -X POST \ -H "authorization: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "app_id": "app_123", "version_id": 456, "link": "https://github.com/myorg/myapp/releases/tag/v1.0.0", "comment": "Fixed critical bug in authentication" }' \ https://api.capgo.app/bundle/metadata ``` #### Success Response [Section titled “Success Response”](#success-response-2) ```json { "status": "success" } ``` ### PUT [Section titled “PUT”](#put) `https://api.capgo.app/bundle/` Set a bundle to a specific channel. This links a bundle (version) to a channel for distribution. #### Request Body [Section titled “Request Body”](#request-body-2) ```typescript interface SetChannelBody { app_id: string version_id: number // bundle (version) id channel_id: number } ``` #### Example Request [Section titled “Example Request”](#example-request-3) ```bash curl -X PUT \ -H "authorization: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "app_id": "app_123", "version_id": 456, "channel_id": 789 }' \ https://api.capgo.app/bundle/ ``` #### Success Response [Section titled “Success Response”](#success-response-3) ```json { "status": "success", "message": "Bundle 1.0.0 set to channel production" } ``` ## Error Handling [Section titled “Error Handling”](#error-handling) Common error scenarios and their responses: ```json // Bundle not found { "error": "Bundle not found", "status": "KO" } // Invalid bundle (version) format { "error": "Invalid version format", "status": "KO" } // Storage error { "error": "Failed to delete bundle from storage", "status": "KO" } // Permission denied { "error": "Insufficient permissions to manage bundles", "status": "KO" } ``` ## Common Use Cases [Section titled “Common Use Cases”](#common-use-cases) 1. **Cleanup Old Bundles (Versions)** ```typescript // Delete outdated beta bundles (versions) { "app_id": "app_123", "version": "1.0.0-beta.1" } ``` 2. **App Reset** ```typescript // Remove all bundles to start fresh { "app_id": "app_123" } ``` ## Storage Considerations [Section titled “Storage Considerations”](#storage-considerations) 1. **Retention Policy**: Define how long to keep old bundles 2. **Size Management**: Monitor bundle sizes and storage usage 3. **Backup Strategy**: Consider backing up critical bundles (versions) 4. **Cost Optimization**: Remove unnecessary bundles to optimize storage costs # Channels > Guide to managing app update channels in Capgo, covering bundle (version) control, platform targeting, and update policies. Channels are the core mechanism for managing app updates in Capgo. They allow you to control how and when your users receive updates, enabling features like A/B testing, staged rollouts, and platform-specific updates. ## Understanding Channels [Section titled “Understanding Channels”](#understanding-channels) A channel represents a distribution track for your app updates. Each channel can be configured with specific rules and constraints: * **Bundle (version) Control**: Specify which bundle (version) users receive * **Platform Targeting**: Target specific platforms (iOS/Android/Electron) * **Update Policies**: Control how updates are delivered * **Device Restrictions**: Manage which devices can access updates ## Channel Configuration Options [Section titled “Channel Configuration Options”](#channel-configuration-options) * **public**: Set as default channel for new devices * **disableAutoUpdateUnderNative**: Prevent updates when the device’s native app version is newer than the update bundle (version) available in the channel (e.g., device is on native app version 1.2.3, but channel has bundle (version) 1.2.2) * **disableAutoUpdate**: Control update behavior (“major”, “minor”, “version\_number”, “none”) * **ios/android/electron**: Enable/disable for specific platforms * **allow\_device\_self\_set**: Let devices choose their channel * **allow\_emulator**: Allow updates on emulator devices * **allow\_dev**: Allow updates on development builds ## Best Practices [Section titled “Best Practices”](#best-practices) 1. **Testing Channel**: Maintain a testing channel for internal validation 2. **Staged Rollout**: Use multiple channels for gradual update deployment 3. **Platform Separation**: Create separate channels for iOS, Android, and Electron when needed 4. **Bundle (version) Control**: Use semantic versioning for clear update paths ## Endpoints [Section titled “Endpoints”](#endpoints) ### POST [Section titled “POST”](#post) `https://api.capgo.app/channel/` Create or update a channel configuration. #### Request Body [Section titled “Request Body”](#request-body) ```typescript type disable_update = "major" | "minor" | "version_number" | "none" interface ChannelSet { app_id: string channel: string version?: string // bundle (version) name public?: boolean disableAutoUpdateUnderNative?: boolean disableAutoUpdate?: disable_update ios?: boolean android?: boolean electron?: boolean allow_device_self_set?: boolean allow_emulator?: boolean allow_dev?: boolean } ``` #### Example Request [Section titled “Example Request”](#example-request) ```bash curl -X POST \ -H "authorization: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "app_id": "app_123", "channel": "beta", "version": "1.2.0", "public": false, "disableAutoUpdate": "minor", "ios": true, "android": true, "electron": true, "allow_emulator": true }' \ https://api.capgo.app/channel/ ``` #### Success Response [Section titled “Success Response”](#success-response) ```json { "status": "ok" } ``` ### GET [Section titled “GET”](#get) `https://api.capgo.app/channel/` Retrieve channel information. Returns 50 channels per page. #### Query Parameters [Section titled “Query Parameters”](#query-parameters) * `app_id`: Required. The ID of your app * `page`: Optional. Page number for pagination * `channel`: Optional. Specific channel name to retrieve #### Example Requests [Section titled “Example Requests”](#example-requests) ```bash # Get all channels curl -H "authorization: your-api-key" \ "https://api.capgo.app/channel/?app_id=app_123" # Get specific channel curl -H "authorization: your-api-key" \ "https://api.capgo.app/channel/?app_id=app_123&channel=beta" # Get next page curl -H "authorization: your-api-key" \ "https://api.capgo.app/channel/?app_id=app_123&page=1" ``` #### Response Type [Section titled “Response Type”](#response-type) ```typescript interface Channel { id: number; created_at: string; name: string; app_id: string; version: { // bundle (version) assigned to the channel id: number, name: string }; created_by: string; updated_at: string; public: boolean; disableAutoUpdateUnderNative: boolean; disableAutoUpdate: boolean; allow_emulator: boolean; allow_dev: boolean; } ``` In the response below, `version` refers to the bundle (version) assigned to the channel. #### Example Response [Section titled “Example Response”](#example-response) ```json { "data": [ { "id": 1, "name": "production", "app_id": "app_123", "version": { "id": 1, "name": "1.0.0" }, "created_at": "2024-01-01T00:00:00Z", "updated_at": "2024-01-01T00:00:00Z", "created_by": "user_123", "public": true, "disableAutoUpdateUnderNative": false, "disableAutoUpdate": false, "allow_emulator": false, "allow_dev": false } ] } ``` ### DELETE [Section titled “DELETE”](#delete) `https://api.capgo.app/channel/` Delete a channel. Note that this will affect all devices using this channel. #### Query Parameters [Section titled “Query Parameters”](#query-parameters-1) ```typescript interface Channel { channel: string app_id: string } ``` #### Example Request [Section titled “Example Request”](#example-request-1) ```bash curl -X DELETE \ -H "authorization: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "app_id": "app_123", "channel": "beta" }' \ https://api.capgo.app/channel/ ``` #### Success Response [Section titled “Success Response”](#success-response-1) ```json { "status": "ok" } ``` ## Error Handling [Section titled “Error Handling”](#error-handling) Common error scenarios and their responses: ```json // Channel not found { "error": "Channel not found", "status": "KO" } // Invalid bundle (version) format { "error": "Invalid version format. Use semantic versioning", "status": "KO" } // Invalid update policy { "error": "Invalid disableAutoUpdate value", "status": "KO" } // Permission denied { "error": "Insufficient permissions to manage channels", "status": "KO" } ``` ## Common Use Cases [Section titled “Common Use Cases”](#common-use-cases) 1. **Beta Testing** ```typescript { "app_id": "app_123", "channel": "beta", "version": "1.2.0-beta", "public": false, "allow_emulator": true, "allow_dev": true } ``` 2. **Production Rollout** ```typescript { "app_id": "app_123", "channel": "production", "version": "1.2.0", "public": true, "disableAutoUpdate": "minor" } ``` 3. **Platform-Specific Updates** ```typescript { "app_id": "app_123", "channel": "ios-hotfix", "version": "1.2.1", "ios": true, "android": false } ``` # Devices > Docs for managing devices via Capgo API, covering tracking, bundle (version) assignment, and channel management for app installations. Devices represent individual installations of your app that are managed by Capgo. The Devices API allows you to track and manage devices, including their bundles (versions), channels, and update status. Data Retention Device data is retained for **90 days** from the last device activity. Devices that haven’t connected to Capgo within this period will be automatically removed from the system. Active devices are continuously tracked as they check for updates. ## Understanding Devices [Section titled “Understanding Devices”](#understanding-devices) Each device has unique characteristics and states: * **Platform**: iOS, Android, or Electron * **Bundle (version)**: Current bundle (version) and native build version * **Environment**: Production or development, emulator or physical device * **Channel**: Current update channel assignment * **Custom ID**: Optional identifier for your own tracking purposes ## Best Practices [Section titled “Best Practices”](#best-practices) 1. **Bundle (version) Tracking**: Monitor device bundle (version) adoption to ensure update uptake 2. **Channel Management**: Assign devices to appropriate channels based on testing needs 3. **Environment Awareness**: Handle different environments (prod/dev/emulator) appropriately 4. **Custom Identification**: Use custom IDs to integrate with your existing systems ## Endpoints [Section titled “Endpoints”](#endpoints) ### POST [Section titled “POST”](#post) `https://api.capgo.app/device/` Link a device to a specific bundle (version) or channel. #### Request Body [Section titled “Request Body”](#request-body) ```typescript interface DeviceLink { app_id: string device_id: string version_id?: string // bundle (version) name channel?: string // channel name } ``` #### Example Request [Section titled “Example Request”](#example-request) ```bash curl -X POST \ -H "authorization: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "app_id": "app_123", "device_id": "device_456", "channel": "beta" }' \ https://api.capgo.app/device/ ``` #### Success Response [Section titled “Success Response”](#success-response) ```json { "status": "ok" } ``` ### GET [Section titled “GET”](#get) `https://api.capgo.app/device/` Retrieve device information. Uses cursor-based pagination for efficient retrieval of large device lists. #### Query Parameters [Section titled “Query Parameters”](#query-parameters) * `app_id`: Required. The ID of your app * `device_id`: Optional. Specific device ID to retrieve a single device * `cursor`: Optional. Cursor from previous response for pagination * `limit`: Optional. Number of devices per page (default: 50) #### Example Requests [Section titled “Example Requests”](#example-requests) ```bash # Get all devices (first page) curl -H "authorization: your-api-key" \ "https://api.capgo.app/device/?app_id=app_123" # Get specific device curl -H "authorization: your-api-key" \ "https://api.capgo.app/device/?app_id=app_123&device_id=device_456" # Get next page using cursor curl -H "authorization: your-api-key" \ "https://api.capgo.app/device/?app_id=app_123&cursor=2024-01-01T00:00:00Z|device_456" ``` #### Response Type (List) [Section titled “Response Type (List)”](#response-type-list) When requesting multiple devices (no `device_id` parameter): ```typescript interface DeviceListResponse { data: Device[]; nextCursor?: string; // Pass this as 'cursor' param to get next page hasMore: boolean; // true if more pages available } interface Device { updated_at: string; device_id: string; custom_id: string; version?: number; // bundle (version) id version_name: string | null; // bundle (version) name channel?: string; app_id: string; platform: "ios" | "android" | "electron"; plugin_version: string; os_version: string; version_build: string; is_prod: boolean; is_emulator: boolean; key_id: string | null; // First 4 chars of encryption key (e.g., "MIIB") } ``` #### Response Type (Single Device) [Section titled “Response Type (Single Device)”](#response-type-single-device) When requesting a specific device with `device_id` parameter, returns the device object directly: ```typescript interface Device { updated_at: string; device_id: string; custom_id: string; version?: number; // bundle (version) id version_name: string | null; // bundle (version) name channel?: string; app_id: string; platform: "ios" | "android" | "electron"; plugin_version: string; os_version: string; version_build: string; is_prod: boolean; is_emulator: boolean; key_id: string | null; // First 4 chars of encryption key (e.g., "MIIB") } ``` #### Example Response (List) [Section titled “Example Response (List)”](#example-response-list) ```json { "data": [ { "device_id": "device_456", "custom_id": "test-device-1", "version": 1, "version_name": "1.0.0", "app_id": "app_123", "platform": "ios", "plugin_version": "5.0.0", "os_version": "17.0", "version_build": "1", "is_prod": true, "is_emulator": false, "updated_at": "2024-01-01T00:00:00Z" } ], "nextCursor": "2024-01-01T00:00:00Z|device_456", "hasMore": true } ``` #### Example Response (Single Device) [Section titled “Example Response (Single Device)”](#example-response-single-device) ```json { "device_id": "device_456", "custom_id": "test-device-1", "version": 1, "version_name": "1.0.0", "app_id": "app_123", "platform": "ios", "plugin_version": "5.0.0", "os_version": "17.0", "version_build": "1", "is_prod": true, "is_emulator": false, "updated_at": "2024-01-01T00:00:00Z", "channel": "production" } ``` ### DELETE [Section titled “DELETE”](#delete) `https://api.capgo.app/device/` Unlink a device from its channel override. This resets the device to use its default channel. Delete device Device data is retained for **90 days** from the last device activity. Devices that haven’t connected to Capgo within this period will be automatically removed from the system. Active devices are continuously tracked as they check for updates. You can’t delete a device with this endpoint, it only affect the channel override. #### Query Parameters [Section titled “Query Parameters”](#query-parameters-1) ```typescript interface Device { device_id: string app_id: string } ``` #### Example Request [Section titled “Example Request”](#example-request-1) ```bash curl -X DELETE \ -H "authorization: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "app_id": "app_123", "device_id": "device_456" }' \ https://api.capgo.app/device/ ``` #### Success Response [Section titled “Success Response”](#success-response-1) ```json { "status": "ok" } ``` ## Error Handling [Section titled “Error Handling”](#error-handling) Common error scenarios and their responses: ```json // Device not found { "error": "Device not found", "status": "KO" } // Invalid bundle (version) { "error": "Version not found", "status": "KO" } // Invalid channel { "error": "Channel not found", "status": "KO" } // Permission denied { "error": "Insufficient permissions to manage devices", "status": "KO" } ``` ## Common Use Cases [Section titled “Common Use Cases”](#common-use-cases) 1. **Beta Device Registration** ```typescript { "app_id": "app_123", "device_id": "device_456", "channel": "beta" } ``` 2. **Version Override** ```typescript { "app_id": "app_123", "device_id": "device_456", "version_id": "1.1.0" } ``` 3. **Reset to Default Channel** ```typescript // Use DELETE endpoint to remove overrides ``` ## Tips for Device Management [Section titled “Tips for Device Management”](#tips-for-device-management) 1. **Monitoring**: Regularly check device status and bundle (version) distribution 2. **Testing**: Use custom IDs to identify test devices easily 3. **Troubleshooting**: Track device updates and channel assignments 4. **Native Version Control**: Monitor native app versions to ensure compatibility # Members > Comprehensive guide to managing organization members in Capgo, covering roles, permissions, and best practices for security and collaboration. Organization members are users who have access to your Capgo organization. Each member has a specific role that determines their permissions within the organization. Managing members effectively is crucial for maintaining security and collaboration in your team. ## Member Roles [Section titled “Member Roles”](#member-roles) ### Regular Roles [Section titled “Regular Roles”](#regular-roles) * **read**: Can view resources but cannot make changes * **upload**: Can upload new bundles and view resources * **write**: Can modify resources and upload bundles * **admin**: Can manage organization settings and members * **super\_admin**: Has full control over the organization ### Invite Roles [Section titled “Invite Roles”](#invite-roles) * **invite\_read**: Pending invitation for read access * **invite\_upload**: Pending invitation for upload access * **invite\_write**: Pending invitation for write access * **invite\_admin**: Pending invitation for admin access * **invite\_super\_admin**: Pending invitation for super admin access ## Best Practices [Section titled “Best Practices”](#best-practices) 1. **Role Assignment**: Follow the principle of least privilege when assigning roles 2. **Regular Audits**: Periodically review member access and remove unused accounts 3. **Onboarding**: Have a clear process for adding new members and assigning roles 4. **Offboarding**: Promptly remove access for members who leave the organization ## Endpoints [Section titled “Endpoints”](#endpoints) ### POST [Section titled “POST”](#post) `https://api.capgo.app/organization/members/` Add a new member to an organization or update an existing member’s role. Note that you can only invite users who already have a Capgo account - the email must correspond to an existing Capgo user. #### Request Body [Section titled “Request Body”](#request-body) ```typescript interface MemberCreate { orgId: string email: string role: "read" | "upload" | "write" | "admin" | "super_admin" } ``` #### Example Request [Section titled “Example Request”](#example-request) ```bash curl -X POST \ -H "authorization: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "orgId": "org_123", "email": "newmember@example.com", "role": "write" }' \ https://api.capgo.app/organization/members/ ``` #### Success Response [Section titled “Success Response”](#success-response) ```json { "status": "OK", "data": { "uid": "user_789", "email": "newmember@example.com", "role": "invite_write", "image_url": null } } ``` Notes: * When adding a new member, they will receive an invitation email. Their role will be prefixed with “invite\_” until they accept the invitation. * The user must already have a Capgo account before they can be invited. If they don’t have an account, they should first create one at <https://console.capgo.app/register/> ### GET [Section titled “GET”](#get) `https://api.capgo.app/organization/members/` Retrieve all members of an organization. #### Query Parameters [Section titled “Query Parameters”](#query-parameters) ```typescript interface MemberQuery { orgId: string } ``` #### Response Type [Section titled “Response Type”](#response-type) ```typescript interface Member { uid: string; email: string; image_url: string; role: "invite_read" | "invite_upload" | "invite_write" | "invite_admin" | "invite_super_admin" | "read" | "upload" | "write" | "admin" | "super_admin"; } ``` #### Example Request [Section titled “Example Request”](#example-request-1) ```bash curl -H "authorization: your-api-key" \ "https://api.capgo.app/organization/members/?orgId=org_123" ``` #### Example Response [Section titled “Example Response”](#example-response) ```json { "data": [ { "uid": "user_123", "email": "john@example.com", "image_url": "https://example.com/avatar.png", "role": "admin" }, { "uid": "user_456", "email": "jane@example.com", "image_url": "https://example.com/avatar2.png", "role": "write" }, { "uid": "user_789", "email": "bob@example.com", "image_url": null, "role": "invite_read" } ] } ``` ### DELETE [Section titled “DELETE”](#delete) `https://api.capgo.app/organization/members/` Remove a member from an organization. This will immediately revoke their access. #### Request Body [Section titled “Request Body”](#request-body-1) ```typescript interface MemberDelete { orgId: string email: string } ``` #### Example Request [Section titled “Example Request”](#example-request-2) ```bash curl -X DELETE \ -H "authorization: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "orgId": "org_123", "email": "user@example.com" }' \ https://api.capgo.app/organization/members/ ``` #### Success Response [Section titled “Success Response”](#success-response-1) ```json { "status": "OK" } ``` ## Error Handling [Section titled “Error Handling”](#error-handling) Common error scenarios and their responses: ```json // Member not found { "error": "Member not found", "status": "KO" } // Invalid role { "error": "Invalid role specified", "status": "KO" } // Permission denied { "error": "Insufficient permissions to manage members", "status": "KO" } // Cannot remove last admin { "error": "Cannot remove the last admin from the organization", "status": "KO" } // Invalid email { "error": "Invalid email format", "status": "KO" } // Member already exists { "error": "Member already exists in organization", "status": "KO" } ``` ## Common Use Cases [Section titled “Common Use Cases”](#common-use-cases) 1. **Team Expansion**: Adding new team members with appropriate roles 2. **Access Control**: Managing member permissions as responsibilities change 3. **Security Audit**: Reviewing member list and roles periodically 4. **Team Restructuring**: Updating roles during organizational changes # Organizations > Guide to managing organizations in Capgo, covering creation, settings, updates, and retrieval of organization details. Organizations are the top-level entities in Capgo. They allow you to group apps, team members, and resources under a single umbrella. Each organization can have multiple members with different roles and permissions. ## Common Use Cases [Section titled “Common Use Cases”](#common-use-cases) * Creating a new organization for your company * Managing organization settings * Updating organization information * Retrieving organization details ## Endpoints [Section titled “Endpoints”](#endpoints) ### GET [Section titled “GET”](#get) `https://api.capgo.app/organization/` Retrieve organization information. If `orgId` is provided in the parameters, returns a single organization. Otherwise, returns all accessible organizations. #### Query Parameters [Section titled “Query Parameters”](#query-parameters) * `orgId` (optional): The ID of the specific organization to retrieve #### Response Type [Section titled “Response Type”](#response-type) ```typescript interface Organization { id: string created_by: string created_at: string updated_at: string logo: string | null name: string management_email: string customer_id: string | null } ``` #### Example Request [Section titled “Example Request”](#example-request) ```bash # Get all organizations curl -H "authorization: your-api-key" https://api.capgo.app/organization/ # Get specific organization curl -H "authorization: your-api-key" https://api.capgo.app/organization/?orgId=org_123 ``` #### Example Response [Section titled “Example Response”](#example-response) ```json { "data": { "id": "org_123", "name": "My Company", "created_at": "2024-01-01T00:00:00Z", "updated_at": "2024-01-01T00:00:00Z", "logo": "https://example.com/logo.png", "management_email": "admin@example.com", "customer_id": "cus_123" } } ``` ### POST [Section titled “POST”](#post) `https://api.capgo.app/organization/` Create a new organization. #### Request Body [Section titled “Request Body”](#request-body) ```typescript interface OrganizationCreate { name: string } ``` #### Example Request [Section titled “Example Request”](#example-request-1) ```bash curl -X POST \ -H "authorization: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "name": "New Organization" }' \ https://api.capgo.app/organization/ ``` #### Example Response [Section titled “Example Response”](#example-response-1) ```json { "status": "Organization created", "id": "org_456" } ``` ### PUT [Section titled “PUT”](#put) `https://api.capgo.app/organization/` Update an existing organization. Requires admin role. #### Request Body [Section titled “Request Body”](#request-body-1) ```typescript interface OrganizationUpdate { orgId: string logo?: string name?: string management_email?: string } ``` #### Example Request [Section titled “Example Request”](#example-request-2) ```bash curl -X PUT \ -H "authorization: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "orgId": "org_123", "name": "New Company Name", "management_email": "newemail@example.com" }' \ https://api.capgo.app/organization/ ``` #### Example Response [Section titled “Example Response”](#example-response-2) ```json { "status": "Organization updated", "data": { "id": "org_123", "name": "New Company Name", "management_email": "newemail@example.com" } } ``` ### DELETE [Section titled “DELETE”](#delete) `https://api.capgo.app/organization/` Delete an existing organization. Requires admin role. This action is irreversible and will remove all associated apps, bundles (versions), and resources. #### Query Parameters [Section titled “Query Parameters”](#query-parameters-1) * `orgId`: The ID of the organization to delete #### Example Request [Section titled “Example Request”](#example-request-3) ```bash curl -X DELETE \ -H "authorization: your-api-key" \ https://api.capgo.app/organization/?orgId=org_123 ``` #### Example Response [Section titled “Example Response”](#example-response-3) ```json { "status": "Organization deleted", "id": "org_123" } ``` ## Error Handling [Section titled “Error Handling”](#error-handling) Common error scenarios and their responses: ```json // Invalid API key { "error": "Invalid API key", "status": "KO" } // Missing required field { "error": "Name is required", "status": "KO" } // Insufficient permissions { "error": "Admin role required", "status": "KO" } ``` ## Best Practices [Section titled “Best Practices”](#best-practices) 1. **Naming**: Use clear, descriptive names for organizations 2. **Roles**: Assign appropriate roles to team members 3. **Email**: Use a group email for management\_email to avoid issues with personal email changes 4. **Logo**: Host logos on a reliable CDN and use HTTPS URLs # Statistics > Detailed guide to Statistics API endpoints, providing insights into Monthly Active Users (MAU), storage, and bandwidth metrics for apps and organizations. The Statistics endpoints provide detailed analytics about your apps and organizations. You can track Monthly Active Users (MAU), storage usage, and bandwidth consumption across different time periods. This data is essential for monitoring app growth, resource usage, and planning capacity. ## Understanding the Metrics [Section titled “Understanding the Metrics”](#understanding-the-metrics) * **MAU (Monthly Active Users)**: Number of unique devices that accessed your app in the last 30 days * **Storage**: Total size of all bundles and resources stored in bytes * **Bandwidth**: Total data transfer for bundle downloads in bytes ## Best Practices [Section titled “Best Practices”](#best-practices) 1. **Regular Monitoring**: Check statistics periodically to track growth and usage patterns 2. **Resource Planning**: Use storage and bandwidth metrics for capacity planning 3. **User Engagement**: Track MAU to understand user engagement trends 4. **Cost Management**: Monitor resource usage to optimize costs ## Endpoints [Section titled “Endpoints”](#endpoints) ### GET /statistics/app/:app\_id/ [Section titled “GET /statistics/app/:app\_id/”](#get-statisticsappapp_id) Get statistics for a specific app. This endpoint is useful for monitoring individual app performance. #### Query Parameters [Section titled “Query Parameters”](#query-parameters) ```typescript interface StatsQuery { from: Date // Start date for the statistics (format: YYYY-MM-DD) to: Date // End date for the statistics (format: YYYY-MM-DD) } ``` #### Example Request [Section titled “Example Request”](#example-request) ```bash curl -H "authorization: your-api-key" \ "https://api.capgo.app/statistics/app/com.demo.app/?from=2024-01-01&to=2024-02-01" ``` #### Example Response [Section titled “Example Response”](#example-response) ```json [ { "date": "2024-01-01", "mau": 1500, "storage": 536870912, // 512MB in bytes "bandwidth": 1073741824 // 1GB in bytes }, { "date": "2024-01-02", "mau": 1550, "storage": 537919488, // 513MB in bytes "bandwidth": 1074790400 // 1.01GB in bytes } ] ``` ### GET /statistics/org/:org\_id/ [Section titled “GET /statistics/org/:org\_id/”](#get-statisticsorgorg_id) Get statistics for a specific organization. Useful for monitoring organization-level usage. #### Query Parameters [Section titled “Query Parameters”](#query-parameters-1) ```typescript interface StatsQuery { from: Date // Start date for the statistics (format: YYYY-MM-DD) to: Date // End date for the statistics (format: YYYY-MM-DD) breakdown: boolean // default false, optional if true it return the breakdown by app noAccumulate: boolean // default false, optional if true it will not accumulate data and just return day by day result } ``` #### Example Request [Section titled “Example Request”](#example-request-1) ```bash curl -H "authorization: your-api-key" \ "https://api.capgo.app/statistics/org/046a36ac-e03c-4590-9257-bd6c9dba9ee8/?from=2024-01-01&to=2024-02-01" ``` #### Example Response [Section titled “Example Response”](#example-response-1) ```json [ { "date": "2024-01-01", "mau": 10000, "storage": 536870912, // 512MB in bytes "bandwidth": 1073741824 // 1GB in bytes }, { "date": "2024-01-02", "mau": 10200, "storage": 537919488, // 513MB in bytes "bandwidth": 1074790400 // 1.01GB in bytes } ] ``` ### GET /statistics/user/ [Section titled “GET /statistics/user/”](#get-statisticsuser) Get aggregated statistics across all organizations you have access to. Perfect for overall usage monitoring. #### Query Parameters [Section titled “Query Parameters”](#query-parameters-2) ```typescript interface StatsQuery { from: Date // Start date for the statistics (format: YYYY-MM-DD) to: Date // End date for the statistics (format: YYYY-MM-DD) } ``` #### Example Request [Section titled “Example Request”](#example-request-2) ```bash curl -H "authorization: your-api-key" \ "https://api.capgo.app/statistics/user/?from=2024-01-01&to=2024-02-01" ``` #### Example Response [Section titled “Example Response”](#example-response-2) ```json [ { "date": "2024-01-01", "mau": 25000, "storage": 1073741824, // 1GB in bytes "bandwidth": 2147483648 // 2GB in bytes }, { "date": "2024-01-02", "mau": 25500, "storage": 1074790400, // 1.01GB in bytes "bandwidth": 2148532224 // 2.01GB in bytes } ] ``` ### GET /statistics/app/:app\_id/bundle\_usage [Section titled “GET /statistics/app/:app\_id/bundle\_usage”](#get-statisticsappapp_idbundle_usage) Get bundle usage statistics for a specific app, showing the distribution of bundles (versions) among users over a specified period. #### Query Parameters [Section titled “Query Parameters”](#query-parameters-3) ```typescript interface BundleUsageQuery { from: Date // Start date for the statistics (format: YYYY-MM-DD) to: Date // End date for the statistics (format: YYYY-MM-DD) } ``` #### Example Request [Section titled “Example Request”](#example-request-3) ```bash curl -H "authorization: your-api-key" \ "https://api.capgo.app/statistics/app/com.demo.app/bundle_usage?from=2024-01-01&to=2024-02-01" ``` #### Example Response [Section titled “Example Response”](#example-response-3) ```json { "labels": ["2024-01-01", "2024-01-02", "2024-01-03"], "datasets": [ { "label": "1.0.0", "data": [60.5, 58.2, 55.3] }, { "label": "1.0.1", "data": [39.5, 41.8, 44.7] } ] } ``` ## Error Handling [Section titled “Error Handling”](#error-handling) Common error scenarios and their responses: ```json // Invalid body { "status": "Invalid body", "error": "Invalid date format or missing parameters" } // Permission denied { "status": "You can't access this app", "error": "Insufficient permissions to access statistics" } // Permission denied for organization { "status": "You can't access this organization", "error": "Insufficient permissions to access organization statistics" } // No organizations found for user statistics { "status": "No organizations found", "error": "No organizations found" } // Internal server error { "status": "Cannot get app statistics", "error": "Internal server error message" } ``` ## Common Use Cases [Section titled “Common Use Cases”](#common-use-cases) 1. **Growth Tracking**: Monitor MAU growth over time 2. **Resource Optimization**: Track storage and bandwidth usage to optimize costs 3. **Capacity Planning**: Use trends to plan for future resource needs 4. **Usage Reports**: Generate periodic usage reports for stakeholders 5. **Bundle (version) Distribution Analysis**: Understand how users are distributed across different app bundles (versions) with bundle usage statistics ## Tips for Analysis [Section titled “Tips for Analysis”](#tips-for-analysis) 1. **Compare Periods**: Look at month-over-month or year-over-year trends 2. **Track Ratios**: Monitor bandwidth per user or storage per app 3. **Set Alerts**: Create alerts for unusual spikes in usage 4. **Regular Backups**: Export statistics regularly for historical analysis 5. **Bundle (version) Adoption**: Use bundle usage to track adoption rates of new bundles (versions) # Migrate from AppFlow to Capgo > Detailed walkthrough for moving an Ionic AppFlow project to Capgo. Each step maps to the standard AppFlow migration tasks so you can compare line by line—and see which ones Capgo already handles for you. > 🚦 Ionic announced that AppFlow’s commercial products—including Live Updates—are winding down. Existing projects can run until **31 December 2027**, but no new customers are accepted and no new features are planned. This guide walks you through the actions required to migrate to Capgo and highlights the native automation you gain. ## Migration overview [Section titled “Migration overview”](#migration-overview) Capgo handles channels, bundle retention, rollbacks, analytics, and CLI uploads for you. Migration boils down to installing the plugin, calling `CapacitorUpdater.notifyAppReady()`, and—if desired—configuring optional manual controls. The sections below walk through each task directly. Version Targeting Like AppFlow If you relied on AppFlow’s automatic version matching (delivering compatible updates based on native version), Capgo provides the same capability with enhanced control. See the [Version Targeting Guide](/docs/live-updates/version-targeting) for detailed strategies on managing updates across multiple app versions. ## Step 0 – Capture your current AppFlow setup [Section titled “Step 0 – Capture your current AppFlow setup”](#step0-capture-your-current-appflow-setup) * Note your AppFlow **App ID**, existing channels, and signing keys. * Export any bundle history you want to archive. * If you are using GitHub Actions or another CI provider, keep those pipelines—they will keep working with Capgo. ## Step 1 – Replace the AppFlow SDK with Capgo [Section titled “Step 1 – Replace the AppFlow SDK with Capgo”](#step1-replace-the-appflow-sdk-with-capgo) ```bash npm uninstall @capacitor/live-updates npm install @capgo/capacitor-updater npx cap sync ``` That’s it. Capgo bundles the native code for both iOS and Android; no extra JavaScript helpers are required. ## Step 2 – Minimal configuration (no manual fields) [Section titled “Step 2 – Minimal configuration (no manual fields)”](#step2-minimal-configuration-no-manual-fields) The existing configuration block is extensive. Capgo auto-detects your project and channels, so the minimal configuration is: capacitor.config.ts ```ts import { CapacitorConfig } from '@capacitor/cli' const config: CapacitorConfig = { plugins: { CapacitorUpdater: { autoUpdate: true, autoDeletePrevious: true, }, }, } export default config ``` ### Configuration quick reference [Section titled “Configuration quick reference”](#configuration-quick-reference) | Ionic AppFlow setting | Capgo equivalent | Do you need to set it? | | ---------------------------- | ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | | `appId` | Managed in the Capgo dashboard | Automatically supplied when you create the project | | `channel` / `defaultChannel` | Channel rules in the dashboard/API | Optional override; defaults come from the server. See [Version Targeting](/docs/live-updates/version-targeting) for multi-version strategies | | `autoUpdateMethod` | `autoUpdate: true` | Enabled by default | | `maxVersions` | Retention policy | Configured centrally (1 month default, 24 months max) | | `enabled` | Not required | Capgo toggles availability per channel | ## Step 3 – Call `notifyAppReady()` (the only required hook) [Section titled “Step 3 – Call notifyAppReady() (the only required hook)”](#step3-call-notifyappready-the-only-required-hook) In Ionic’s guide you wire `sync`, `download`, and `reload`, then hide the splash screen manually. Capgo performs those actions natively. You only need to confirm the app is ready: ```ts import { CapacitorUpdater } from '@capgo/capacitor-updater' CapacitorUpdater.notifyAppReady() ``` If the confirmation never arrives, Capgo rolls the bundle back automatically. **That’s it—Capgo handles the background checks, splash visibility, and rollbacks for you.** Optional: run logic before the splash screen hides ```ts import { CapacitorUpdater } from '@capgo/capacitor-updater' import { SplashScreen } from '@capacitor/splash-screen' CapacitorUpdater.addListener('appReady', () => { // Log diagnostics or run custom code if needed SplashScreen.hide() }) CapacitorUpdater.notifyAppReady() ``` ## Step 4 – Update strategies translated [Section titled “Step 4 – Update strategies translated”](#step4-update-strategies-translated) AppFlow documents three strategies. Here is how they map to Capgo: ### Background (default) [Section titled “Background (default)”](#background-default) * **AppFlow**: configure `autoUpdateMethod = background`, call `sync()` manually. * **Capgo**: enabled by default. No JavaScript required. ### Always latest [Section titled “Always latest”](#always-latest) * **AppFlow**: add an `App.addListener('resume')` handler that downloads and reloads. * **Capgo**: auto-update runs on resume already. Add the handler only if you want a custom timing window. Optional: manual resume check ```ts import { App } from '@capacitor/app' import { CapacitorUpdater } from '@capgo/capacitor-updater' App.addListener('resume', async () => { const bundle = await CapacitorUpdater.download() if (bundle) { await CapacitorUpdater.set({ id: bundle.id }) } }) ``` ### Force update [Section titled “Force update”](#force-update) * **AppFlow**: prompt the user and call `reload()`. * **Capgo**: mark the bundle as “mandatory” in the dashboard, then listen for the `majorAvailable` event (emitted after `notifyAppReady()`) to prompt or force users inside your app. ## Step 5 – Mapping API calls [Section titled “Step 5 – Mapping API calls”](#step5-mapping-api-calls) | AppFlow method | Capgo equivalent | Do you need it? | | -------------------------- | ----------------------------- | ---------------------------------------------------------- | | `LiveUpdates.sync()` | Handled automatically | Capgo’s native auto-update runs without a manual sync call | | `LiveUpdates.download()` | `CapacitorUpdater.download()` | Optional for custom flows | | `LiveUpdates.reload()` | `CapacitorUpdater.set()` | Optional; dashboard toggles handle forced updates | | `LiveUpdates.getVersion()` | `CapacitorUpdater.current()` | Optional diagnostics | ## Step 6 – Deploy using the Capgo CLI or API [Section titled “Step 6 – Deploy using the Capgo CLI or API”](#step6-deploy-using-the-capgo-cli-or-api) Finish the migration by uploading bundles with the Capgo CLI or API. The workflow mirrors what you may have scripted before, but now includes native safeguards: ```bash capgo login # authenticate once capgo bundle upload \ --path dist \ --channel production # automatically tags platform/version ``` ### Version-specific deployments (like AppFlow) [Section titled “Version-specific deployments (like AppFlow)”](#version-specific-deployments-like-appflow) If you need to target specific native versions (similar to AppFlow’s native version locking): ```bash # Only deliver to devices on native version 2.0.0 or higher capgo bundle upload \ --path dist \ --channel production \ --native-version "2.0.0" # Use channels for different major versions capgo bundle upload --channel v2 # for app version 2.x capgo bundle upload --channel v3 # for app version 3.x ``` See the [Version Targeting Guide](/docs/live-updates/version-targeting) for comprehensive strategies. Capgo automatically: * Keeps device-level audit logs for every install. * Sends proactive emails when you approach plan limits. * Provides burst credits so you are never blocked mid-release. * Publishes latency metrics for 18 global regions at [status.capgo.app/history](https://status.capgo.app/history). ## Ionic enterprise plugins [Section titled “Ionic enterprise plugins”](#ionic-enterprise-plugins) If your Ionic stack also uses enterprise plugins, follow the targeted migration docs below. Each guide recommends the Capgo replacement and the next steps. * [Migrate from Ionic Secure Storage](/docs/upgrade/from-ionic-secure-storage) * [Migrate from Ionic Auth Connect](/docs/upgrade/from-ionic-auth-connect) * [Migrate from Ionic Identity Vault](/docs/upgrade/from-ionic-identity-vault) ## Frequently asked questions [Section titled “Frequently asked questions”](#frequently-asked-questions) ### Why is AppFlow shutting down live updates? [Section titled “Why is AppFlow shutting down live updates?”](#why-is-appflow-shutting-down-live-updates) Ionic is discontinuing commercial products, including AppFlow, to focus on their open-source framework. Existing customers can continue using live updates until **31 December 2027**, but no new features or customers are accepted. Capgo fills that gap with a dedicated native OTA platform. ### How long does migration take? [Section titled “How long does migration take?”](#how-long-does-migration-take) Most teams complete the move in under a day. Concepts such as channels, deployments, and release rules map directly, and our team provides documentation plus hands-on support. In many cases you simply install the plugin, call `notifyAppReady()`, and upload your first bundle. ### Will we save money? [Section titled “Will we save money?”](#will-we-save-money) Yes. AppFlow live updates start at **$499/mo**. Capgo starts at **$14/mo** with usage-based pricing that drops to roughly **$0.001 per MAU**. You also gain encryption, automatic rollbacks, and worldwide latency monitoring. ### When should we migrate? [Section titled “When should we migrate?”](#when-should-we-migrate) Because AppFlow is now in maintenance mode, migrating sooner gives you access to ongoing Capgo innovation. We recommend switching when it fits your release schedule. Our engineering team will help you plan the changeover so your CI/CD and deployments keep running. ## Additional Resources [Section titled “Additional Resources”](#additional-resources) * **[Version Targeting Guide](/docs/live-updates/version-targeting)** - Deep dive into AppFlow-style version matching strategies * **[Breaking Changes](/docs/live-updates/breaking-changes)** - Managing major version updates with channels * **[Channel Management](/docs/live-updates/channels)** - Complete channel configuration reference ## Need help? [Section titled “Need help?”](#need-help) * Book a migration session: [cal.com/team/capgo/demo](https://cal.com/team/capgo/demo) * Join the community: [Capgo Discord](https://discord.gg/VCXxSVjefW) * Track issues / request features: [github.com/Cap-go/capacitor-updater](https://github.com/Cap-go/capacitor-updater) Capgo is engineered for enterprises that need native delta updates, encrypted bundles, and continuous innovation. Once you migrate you can delete the AppFlow glue code, rely on native automation, and keep shipping without interruption. # Migrate from Capawesome Cloud to Capgo > Step-by-step guide to move from Capawesome Cloud to Capgo while gaining native OTA safety, device-level observability, and full automation. > ⚡️ Capgo automates channels, bundle cleanup, rollbacks, analytics, and CLI uploads natively. Use this guide to perform the minimal steps required to migrate and optionally recreate any custom behaviour you still need. ## Overview [Section titled “Overview”](#overview) 1. Gather your existing Capawesome Cloud configuration (App ID, channels, signing keys, CLI tokens) so you can archive or audit it later. 2. Install the Capgo plugin, remove the Capawesome SDK, and call `CapacitorUpdater.notifyAppReady()`. 3. Configure optional behaviour (manual downloads, pinning bundles, reloads) if you rely on those flows today. With Capgo you only need to install our plugin and call `CapacitorUpdater.notifyAppReady()`. Everything else—channels, bundle cleanup, rollbacks, analytics, and CLI automation—is handled natively. The sections below walk through each task directly. ## Before you start [Section titled “Before you start”](#before-you-start) * Make sure your project is already using Capacitor 5 or later. * Install the Capgo CLI (`npm install -g @capgo/cli`) if you plan to push bundles from CI/CD. ## Step 1 – Install Capgo and remove the Capawesome SDK [Section titled “Step 1 – Install Capgo and remove the Capawesome SDK”](#step1-install-capgo-and-remove-the-capawesome-sdk) ```bash npm uninstall @capawesome/capacitor-live-update npm install @capgo/capacitor-updater npx cap sync ``` That is the only mandatory swap. Capgo’s native code ships with the plugin; no extra JavaScript helpers are required. ## Step 2 – Minimal configuration [Section titled “Step 2 – Minimal configuration”](#step2-minimal-configuration) The previous setup required mapping dozens of options in `capacitor.config`. Capgo recognises your project automatically, so the minimal configuration looks like this: capacitor.config.ts ```ts import { CapacitorConfig } from '@capacitor/cli' const config: CapacitorConfig = { plugins: { CapacitorUpdater: { autoUpdate: true, autoDeletePrevious: true, periodCheckDelay: 10 * 60 * 1000, // optional: check every 10 minutes }, }, } export default config ``` Everything Capawesome lists as manual flags (`defaultChannel`, `autoDeleteBundles`, retention policies, etc.) is managed through the Capgo dashboard or API. You only need to override these keys if you want behaviour that differs from Capgo’s defaults. ### Configuration quick reference [Section titled “Configuration quick reference”](#configuration-quick-reference) | Capawesome option | Capgo equivalent | Do you need to set it? | | ------------------------- | -------------------------------------------------------- | -------------------------------------------------------------- | | `appId` | Taken from the Capgo dashboard once you create a project | Only if you use multiple projects in one binary | | `defaultChannel` | Channel rules managed in the dashboard/API | Optional; most teams set this server-side | | `autoDeleteBundles` | `autoDeletePrevious: true` (default) | Already enabled | | `publicKey` | Managed in Capgo console | Only if you rotate keys manually | | `maxVersions` / retention | Bundle retention policy | Configured centrally in Capgo (1 month default, 24 months max) | ## Step 3 – Call `notifyAppReady()` (the only required hook) [Section titled “Step 3 – Call notifyAppReady() (the only required hook)”](#step3-call-notifyappready-the-only-required-hook) The old workflow introduced custom listeners (`checkForUpdates()`, `retryDownload()`, hiding the splash screen, etc.). Capgo performs those steps natively. The only API you must call is: ```ts import { CapacitorUpdater } from '@capgo/capacitor-updater' CapacitorUpdater.notifyAppReady() ``` This confirms the app booted successfully. If the confirmation never arrives, Capgo automatically rolls back the bundle—no extra JavaScript needed. **That’s it—Capgo handles background checks, splash visibility, and rollbacks natively.** Optional: run custom logic before the splash screen hides ```ts import { CapacitorUpdater } from '@capgo/capacitor-updater' import { SplashScreen } from '@capacitor/splash-screen' CapacitorUpdater.addListener('appReady', () => { // Run diagnostics or logging if you need to SplashScreen.hide() }) CapacitorUpdater.notifyAppReady() ``` ## Step 4 – Map API calls (mostly optional) [Section titled “Step 4 – Map API calls (mostly optional)”](#step4-map-api-calls-mostly-optional) In Capgo you normally let the auto-updater run; manual APIs remain available if you want full control. | Capawesome Cloud | Capgo equivalent | Do you need it? | | -------------------------------- | ------------------------------ | ------------------------------------------------------------------- | | `LiveUpdate.fetchLatestBundle()` | `CapacitorUpdater.getLatest()` | Only when implementing your own download workflow | | `LiveUpdate.downloadBundle()` | `CapacitorUpdater.download()` | Optional: native auto-update already downloads | | `LiveUpdate.setNextBundle()` | `CapacitorUpdater.next()` | Optional: dashboard pins bundles automatically | | `LiveUpdate.reload()` | `CapacitorUpdater.reload()` | Optional; Capgo enforces mandatory bundles after `notifyAppReady()` | | `LiveUpdate.getCurrentBundle()` | `CapacitorUpdater.current()` | Optional diagnostics | If you stick with the native auto-update behaviour you can delete the Capawesome JavaScript entirely. ### Manual control examples [Section titled “Manual control examples”](#manual-control-examples) **Download the latest bundle** Capgo ```ts import { CapacitorUpdater } from '@capgo/capacitor-updater' const downloadUpdate = async () => { const latest = await CapacitorUpdater.getLatest() if (latest?.url) { const bundle = await CapacitorUpdater.download({ url: latest.url, version: latest.version, }) console.log('Bundle downloaded', bundle?.id) } } ``` Capawesome Cloud ```ts import { LiveUpdate } from '@capawesome/capacitor-live-update' const downloadUpdate = async () => { const result = await LiveUpdate.fetchLatestBundle() if (result.downloadUrl) { await LiveUpdate.downloadBundle({ bundleId: result.bundleId, url: result.downloadUrl, }) console.log('Bundle downloaded') } } ``` **Set the next bundle** Capgo ```ts import { CapacitorUpdater } from '@capgo/capacitor-updater' const setNextBundle = async () => { await CapacitorUpdater.next({ id: 'bundle-id-123' }) } ``` Capawesome Cloud ```ts import { LiveUpdate } from '@capawesome/capacitor-live-update' const setNextBundle = async () => { await LiveUpdate.setNextBundle({ bundleId: 'bundle-id-123' }) } ``` **Apply the downloaded bundle immediately** Capgo ```ts import { CapacitorUpdater } from '@capgo/capacitor-updater' const applyUpdate = async () => { await CapacitorUpdater.reload() } ``` Capawesome Cloud ```ts import { LiveUpdate } from '@capawesome/capacitor-live-update' const applyUpdate = async () => { await LiveUpdate.reload() } ``` ## Step 5 – Update strategies: how Capgo handles them [Section titled “Step 5 – Update strategies: how Capgo handles them”](#step5-update-strategies-how-capgo-handles-them) Capawesome documents three strategies. Here’s how they translate: ### Background updates [Section titled “Background updates”](#background-updates) * **Previous workflow**: configure in code and schedule downloads manually. * **Capgo**: enabled by default (`autoUpdate: true`). No additional code required. ### Always latest [Section titled “Always latest”](#always-latest) * **Previous workflow**: add an `App.resume` listener, call `download`, then `set`. * **Capgo**: background auto-update already performs the check after resume. You only need the manual listener if you want a custom interval. Optional: manual resume check ```ts import { App } from '@capacitor/app' import { CapacitorUpdater } from '@capgo/capacitor-updater' App.addListener('resume', async () => { const latest = await CapacitorUpdater.getLatest() if (latest?.url) { const downloaded = await CapacitorUpdater.download({ url: latest.url, version: latest.version, }) if (downloaded) { await CapacitorUpdater.next({ id: downloaded.id }) } } }) ``` ### Force update [Section titled “Force update”](#force-update) * **Previous workflow**: wire prompt logic and enforce reload. * **Capgo**: mark the bundle as “mandatory” in the dashboard, then listen for the `majorAvailable` event (emitted after `notifyAppReady()`) to require users to upgrade inside your app. ## Step 6 – Deploying bundles [Section titled “Step 6 – Deploying bundles”](#step6-deploying-bundles) If you previously relied on `capawesome live-update deploy`, Capgo offers a similar CLI workflow, and you can also automate deployments entirely via API. ```bash # Authenticate once (stores a token in your CI environment) capgo login # Upload a new bundle (auto-detects platform/version) capgo bundle upload --path dist --channel production ``` Because Capgo tracks bundle health automatically, you also get: * Device-level audit logs for every install. * Automatic retention (one month by default) with configurable limits up to 24 months. * Real-time latency metrics at [status.capgo.app/history](https://status.capgo.app/history). ## Migration timeline [Section titled “Migration timeline”](#migration-timeline) * **Inventory & install**: 10 minutes (`npm install`, remove old plugin). * **Config & readiness**: 5 minutes (`notifyAppReady`). * **Sanity checks**: 15 minutes (optional manual tests or listeners). * **First deployment**: 10 minutes with Capgo CLI or CI integration. In practice teams finish in under an hour. If you provide Capawesome project details we can even import channels and device lists for you. ## Capgo support [Section titled “Capgo support”](#capgo-support) * **Migration concierge**: book a session at [cal.com/team/capgo/demo](https://cal.com/team/capgo/demo). * **Community**: join the [Capgo Discord](https://discord.gg/VCXxSVjefW). * **Issue tracker**: [github.com/Cap-go/capacitor-updater/issues](https://github.com/Cap-go/capacitor-updater/issues). Capgo is built for long-term reliability: native delta updates, encrypted bundles, automatic rollbacks, and analytics that do not require custom JavaScript. Once you migrate you can delete the maintenance-heavy glue and let the platform run updates automatically. # Migrate from Ionic Auth Connect > Move from Ionic Auth Connect to Capgo Social Login with OAuth2 support. Ionic Auth Connect handles enterprise OAuth and OIDC flows. Capgo’s Social Login plugin provides provider-native sign-in for Google, Apple, Facebook, Twitter, and generic OAuth2 providers. ## Capgo replacements at a glance [Section titled “Capgo replacements at a glance”](#capgo-replacements-at-a-glance) | Ionic enterprise plugin | Capgo replacement | Migration guide | | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- | | Secure Storage | [@capgo/capacitor-fast-sql](/docs/plugins/fast-sql/) or [@capgo/capacitor-data-storage-sqlite](/docs/plugins/data-storage-sqlite/) | [Secure Storage migration](/docs/upgrade/from-ionic-secure-storage) | | Auth Connect | [@capgo/capacitor-social-login](/docs/plugins/social-login/) | You are here | | Identity Vault | [@capgo/capacitor-native-biometric](/docs/plugins/native-biometric/) | [Identity Vault migration](/docs/upgrade/from-ionic-identity-vault) | ## Migration steps [Section titled “Migration steps”](#migration-steps) 1. **Inventory your providers** (Google, Apple, Facebook, Azure AD, Auth0, Okta, etc.) and the redirect URLs you currently use. 2. **Install Social Login** and sync native code. ```bash npm install @capgo/capacitor-social-login npx cap sync ``` 3. **Configure each provider** using the Social Login docs (client IDs, bundle IDs, OAuth redirect URIs). 4. **Update your auth flow** to call Social Login provider methods instead of Auth Connect. Store refresh tokens in a secure store (Fast SQL or Data Storage SQLite) if you rely on long-lived sessions. 5. **Remove Ionic Auth Connect** from your dependencies and native configuration. ## Next steps [Section titled “Next steps”](#next-steps) * [Social Login getting started](/docs/plugins/social-login/getting-started/) * [Secure Storage migration](/docs/upgrade/from-ionic-secure-storage) * [Identity Vault migration](/docs/upgrade/from-ionic-identity-vault) # Migrate from Ionic Identity Vault > Replace Ionic Identity Vault with Capgo Native Biometric and secure storage plugins. Ionic Identity Vault combines biometric gating with encrypted storage. Capgo replaces that stack with Native Biometric for user verification plus Fast SQL or Data Storage SQLite for encrypted persistence. ## Capgo replacements at a glance [Section titled “Capgo replacements at a glance”](#capgo-replacements-at-a-glance) | Ionic enterprise plugin | Capgo replacement | Migration guide | | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- | | Secure Storage | [@capgo/capacitor-fast-sql](/docs/plugins/fast-sql/) or [@capgo/capacitor-data-storage-sqlite](/docs/plugins/data-storage-sqlite/) | [Secure Storage migration](/docs/upgrade/from-ionic-secure-storage) | | Auth Connect | [@capgo/capacitor-social-login](/docs/plugins/social-login/) | [Auth Connect migration](/docs/upgrade/from-ionic-auth-connect) | | Identity Vault | [@capgo/capacitor-native-biometric](/docs/plugins/native-biometric/) | You are here | ## Migration steps [Section titled “Migration steps”](#migration-steps) 1. **Install Native Biometric** and sync native code. ```bash npm install @capgo/capacitor-native-biometric npx cap sync ``` 2. **Pick a secure storage plugin** (Fast SQL or Data Storage SQLite) to persist tokens or secrets. 3. **Gate sensitive reads/writes** with a biometric prompt before accessing the stored data. 4. **Migrate stored secrets** on first launch by reading from Identity Vault and writing them into the new SQLite store. 5. **Remove Ionic Identity Vault** from your dependencies and native configuration. ## Next steps [Section titled “Next steps”](#next-steps) * [Native Biometric getting started](/docs/plugins/native-biometric/getting-started/) * [Secure Storage migration](/docs/upgrade/from-ionic-secure-storage) * [Auth Connect migration](/docs/upgrade/from-ionic-auth-connect) # Migrate from Ionic Secure Storage > Replace Ionic Secure Storage with Capgo Fast SQL or Data Storage SQLite. Ionic Secure Storage is an enterprise plugin for encrypted key-value data. Capgo provides two SQLite-based options depending on your data model and performance needs. ## Capgo replacements at a glance [Section titled “Capgo replacements at a glance”](#capgo-replacements-at-a-glance) | Ionic enterprise plugin | Capgo replacement | Migration guide | | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- | | Secure Storage | [@capgo/capacitor-fast-sql](/docs/plugins/fast-sql/) or [@capgo/capacitor-data-storage-sqlite](/docs/plugins/data-storage-sqlite/) | You are here | | Auth Connect | [@capgo/capacitor-social-login](/docs/plugins/social-login/) | [Auth Connect migration](/docs/upgrade/from-ionic-auth-connect) | | Identity Vault | [@capgo/capacitor-native-biometric](/docs/plugins/native-biometric/) | [Identity Vault migration](/docs/upgrade/from-ionic-identity-vault) | ## Choose your storage plugin [Section titled “Choose your storage plugin”](#choose-your-storage-plugin) * **Fast SQL**: Best for large datasets, sync workflows, or when you want full SQL control and high throughput. * **Data Storage SQLite**: Best for simple key-value storage with optional encryption and minimal setup. If you are unsure, start with Data Storage SQLite for key-value secrets and move to Fast SQL when you need structured data or high-volume writes. ## Migration steps [Section titled “Migration steps”](#migration-steps) 1. **Pick the storage plugin** that matches your data model. 2. **Install the plugin** and sync native code. ```bash # Option A: Fast SQL npm install @capgo/capacitor-fast-sql # Option B: Data Storage SQLite npm install @capgo/capacitor-data-storage-sqlite npx cap sync ``` 3. **Update storage calls** to the new API surface. Use the Fast SQL or Data Storage SQLite docs for the exact read/write methods. 4. **Migrate existing data** on first launch by reading values from Ionic Secure Storage and writing them into the new SQLite store. 5. **Remove Ionic Secure Storage** from your dependencies and native configuration. ## Next steps [Section titled “Next steps”](#next-steps) * [Fast SQL getting started](/docs/plugins/fast-sql/getting-started/) * [Data Storage SQLite getting started](/docs/plugins/data-storage-sqlite/getting-started/) * [Auth Connect migration](/docs/upgrade/from-ionic-auth-connect) * [Identity Vault migration](/docs/upgrade/from-ionic-identity-vault) # From V2 to V3 > A comprehensive guide on transitioning from version 2 to version 3 of Capgo updater, detailing the necessary steps and considerations for a successful upgrade process This documentation will explain how to upgrade to the version 3 of auto-update. ## First migrate to the last tooling: [Section titled “First migrate to the last tooling:”](#first-migrate-to-the-last-tooling) ```bash npm remove -g capgo npm remove capacitor-updater npm i @capgo/cli npm i @capgo/capacitor-updater@3 npx cap sync ``` ## Remove all your previous config: [Section titled “Remove all your previous config:”](#remove-all-your-previous-config) ```json { CapacitorUpdater: { autoUpdateURL: "https...", ... }, } ``` to only let this: ```json { "CapacitorUpdater": { "autoUpdate": true } } ``` > ⚠️ If you were using your server, with `autoUpdateURL`, I will upgrade this guide soon for you. Meanwhile, take a look at the new upload option `external` which allows you to send only the link of your zip, not the code in Capgo cloud. This has been made for companies with strict privacy policies. In external mode, the code will never land on Capgo server, we just store the URL and send it to the device, which will directly download it. In the standard way, the code is zipped and stored in our server, but we will never open it or use it either. ## What change [Section titled “What change”](#what-change) All configurations become server-side for auto-update, to give you more control on how you send an update to users. That allows us to revert, even deploy just to one user with channels! These settings are added back to the web interface: * disable revert under native * disable update above major > ⚠️ They will become true by default for all channels This will also remove the need to update often the plugin, most updates will be done server side, and you will get it without any change in your side. > ⚠️ Reset when an update becomes the default, so if you prefer not to remove all download versions when updating from the store, do this: ```json { "CapacitorUpdater": { "autoUpdate": true, "resetWhenUpdate": false } } ``` ## Update your code [Section titled “Update your code”](#update-your-code) Lastly, update all your imports in JS from: ```plaintext import { CapacitorUpdater } from 'capacitor-updater' ``` to ```plaintext import { CapacitorUpdater } from '@capgo/capacitor-updater' ``` Then build your code again `npm run build` and copy assets once more `npx cap copy`. You should be able now to test the last auto-update system Send your version with: ```plaintext npx @capgo/cli@latest bundle upload ``` instead of ```plaintext npx capgo upload ``` ## Future evolution [Section titled “Future evolution”](#future-evolution) For now only the first public channel is in use, in the future, public will change for multi public channels, if more than one is set. ## Common problems: [Section titled “Common problems:”](#common-problems) * Build problem after upgrade: if you have already opened the source code of the plugin in Android studio or Xcode, sometimes the sync doesn’t remove them, that the cause of the issue. Open the native IDE and remove `capacitor-updater` by hands and do `npx cap sync` this should solve. # From V3 to V4 > How to upgrade from V3 to V4 of Capgo updater, understand what are the breaking changes and how to handle them ## Why this upgrade [Section titled “Why this upgrade”](#why-this-upgrade) After many talk in the discord community with you. I discovered the manual mode was very too manual and not safe to use, for example, auto-revert was not possible, so if you failed update in manual the user have to remove the app and install back, what is terrible UX. Meanwhile, I took this as an opportunity to give more freedom to you, and remove all bad code I made. ## Install [Section titled “Install”](#install) `npm i @capgo/capacitor-updater@4` ## Auto-update cloud [Section titled “Auto-update cloud”](#auto-update-cloud) If you use the basic example in your app, you are safe to migrate to the new version, enjoy! ## Auto-update self-hosted [Section titled “Auto-update self-hosted”](#auto-update-self-hosted) For you, still simple, the changes are: * The name of the setting from `autoUpdateUrl` in `updateUrl` * The Endpoint method changed from `GET` to POST ## Manual users [Section titled “Manual users”](#manual-users) For you, this is the most significant change, but for the best! You get tons of improvements, Read carefully. ## Changes [Section titled “Changes”](#changes) * `autoUpdateUrl` becomes `updateUrl` since this setting can be used in manual mode now too * Delete of `cancelDelay` and `delayUpdate` in favor of `setDelay` * No more `versionName` in set * Change `version` key, who was returned in most function to object `BundleInfo` ```typescript interface BundleInfo { id: string; version: string; downloaded: string; status: 'success' | 'error' | 'pending' | 'downloading' } ``` * Renamed of misleading names now (even to explain cannot be clear, but at usage is easy to understand the new one): * what was called a `version` is now referring to a `bundle` * `id` refer to the old `version` who was a random string of 10 char, this `id` is the only trustable and unique way to access to your bundles, example `7Dfcd2RedN`. * `version` refer now to the `versionName` you choose for a bundle, example `1.0.0` * `updateUrl` move from `get` to `post`, since custom headers were a problem for some of you and post is more logical, all previous headers go to the body and prefix `cap_` disappear. * `versionName` method is deleted, in favor of `getId` * list returns now a list of `BundleInfo` * Rename `getId` in `getDeviceId` * `autoUpdate` becomes true by default, if you use Manual mode, set it to false. ## News [Section titled “News”](#news) * Method `getLatest`, this method allows you to get from your server set with `updateUrl` the last version available. * Method `setDelay` who take `{`kind`:` “background” | “kill” | “nativeVersion” | “date”, value? : string`}` as argument to set delay to different modes. * Method `next`, to set the version in next backgrounding, in opposite to `set` who do it instantly. * Method `isAutoUpdateEnabled`, to let you know if you are in auto-update context * Event `downloadComplete` when download reach 100% * Added mandatory field `version` in download method * `notifyAppReady` become mandatory in manual mode too, if not call after 10 sec the app reverts to past version. ## Contributors [Section titled “Contributors”](#contributors) [@lincolnthree](https://github.com/lincolnthree/) Thank you so much for starting this work, it was impossible to make this update work without you. # From V4 to V5 > How to upgrade from V4 to V5, of Capgo updater what are the breaking change you should take care of, it's pretty simple ## Why this upgrade [Section titled “Why this upgrade”](#why-this-upgrade) This major version is here to follow Capacitor major version First follow the migration guide of Capacitor: [https://capacitorjs.com/docs/updating/5-0](https://capacitorjs.com/docs/updating/5-0/) ## Install [Section titled “Install”](#install) `npm i @capgo/capacitor-updater@5` `Then sync the native code update:` `npx cap sync` That it ! Pretty easy ! ## Manual mode [Section titled “Manual mode”](#manual-mode) If you were getting yourself the update with getLatest, there are a tiny change. Now if you are up-to-date already it will go into catch. Any response different than update available will do that. # From V5 to V6 > A detailed guide on transitioning from version 5 to version 6 of Capgo updater, outlining the necessary steps and considerations for a successful upgrade process, ensuring compatibility with the latest Capacitor features and improvements. ## Why this upgrade [Section titled “Why this upgrade”](#why-this-upgrade) This major version is here to follow Capacitor major version First follow the migration guide of Capacitor: [https://capacitorjs.com/docs/updating/6-0](https://capacitorjs.com/docs/updating/6-0/) ## Install [Section titled “Install”](#install) `npm i @capgo/capacitor-updater@6` `Then sync the native code update:` `npx cap sync` That it ! Pretty easy ! # From V6 to V7 > A detailed guide on transitioning from version 6 to version 7 of Capgo updater, outlining the necessary steps and considerations for a successful upgrade process, ensuring compatibility with the latest Capacitor features and improvements. ## Why this upgrade [Section titled “Why this upgrade”](#why-this-upgrade) This major version is here to follow Capacitor major version First follow the migration guide of Capacitor: [https://capacitorjs.com/docs/updating/7-0](https://capacitorjs.com/docs/updating/7-0/) ## Install [Section titled “Install”](#install) `npm i @capgo/capacitor-updater@7` `Then sync the native code update:` `npx cap sync` That it ! Pretty easy ! ## Encryption Migration [Section titled “Encryption Migration”](#encryption-migration) If you’re using the `key-v1` encryption method, you’ll need to migrate to the new encryption system as `key-v1` is no longer supported in V7. \[\[memory:96112]] Follow the encryption migration guide here: [Encryption Migration Guide](/docs/cli/migrations/encryption/) ## Configuration Changes [Section titled “Configuration Changes”](#configuration-changes) We recommend adding the following properties in your `capacitor.config` file: * `capacitorUpdater` * `appId` * `version` * `autoUpdate` These settings should help managed better the plugin’s and it’s behaviors. # From V7 to V8 > A detailed guide on transitioning from version 7 to version 8 of Capgo updater, outlining the necessary steps and considerations for a successful upgrade process, ensuring compatibility with Capacitor 8 features and improvements. ## Why this upgrade [Section titled “Why this upgrade”](#why-this-upgrade) This major version is here to follow Capacitor major version 8 First follow the migration guide of Capacitor: [https://capacitorjs.com/docs/updating/8-0](https://capacitorjs.com/docs/updating/8-0/) ## iOS Minimum Version Requirement [Section titled “iOS Minimum Version Requirement”](#ios-minimum-version-requirement) The iOS minimum deployment target has been bumped to **15** to ensure that iOS devices with [CVE-2022-36943](https://nvd.nist.gov/vuln/detail/CVE-2022-36943) are excluded. This is the minimum version of the iOS zip library that has the security fix implemented. ## Install [Section titled “Install”](#install) `npm i @capgo/capacitor-updater@8` Then sync the native code update: `npx cap sync` That’s it! Pretty easy! ## What’s New in V8 [Section titled “What’s New in V8”](#whats-new-in-v8) Version 8 of capacitor-updater brings full compatibility with Capacitor 8, ensuring your app can leverage the latest mobile OS features and improvements. ### Key Updates [Section titled “Key Updates”](#key-updates) * **Capacitor 8 Compatibility**: Full support for Capacitor 8’s enhanced native features * **Performance Improvements**: Optimized update delivery and installation process * **Enhanced Stability**: Bug fixes and stability improvements from v7 * **Maintained API Compatibility**: No breaking changes to the plugin API from v7 ## Configuration [Section titled “Configuration”](#configuration) The configuration remains the same as v7. Your existing `capacitor.config` settings will continue to work: ```typescript { plugins: { CapacitorUpdater: { appId: 'your-app-id', version: '1.0.0', autoUpdate: true, // ... other settings } } } ``` ## Migration Checklist [Section titled “Migration Checklist”](#migration-checklist) * [ ] Follow Capacitor’s v8 [migration guide](https://capacitorjs.com/docs/updating/8-0), check for breaking changes. * [ ] Bump iOS minimum deployment target to 15 (required for CVE-2022-36943 fix) * [ ] [Update](#install) @capgo/capacitor-updater to ^8.0.0 * [ ] [Run](#install) `npx cap sync` * [ ] Test your app thoroughly on both iOS and Android ## Need Help? [Section titled “Need Help?”](#need-help) If you encounter any issues during the migration, please: 1. Check our [documentation](/docs/live-updates/) 2. Visit our [Discord community](https://discord.com/invite/VnYRvBfgA6) 3. Open an issue on [GitHub](https://github.com/Cap-go/capacitor-updater/issues) # Introduction > Introduction to the Capgo webapp, learn how to use the web app of Capgo, to manage your updates and understand what happen with it ## What is this? [Section titled “What is this?”](#what-is-this) Capgo has an extensive webapp to help you manage your projects. This webapp is built with Vue.js and is open source. You can find the source code on [GitHub](https://github.com/Cap-go/capgo/tree/main/src/)\ The webapp is available [here](https://console.capgo.app/).\ This webapp allows you to [manage channels](/docs/webapp/channels/), [manage versions](/docs/webapp/bundles/), [manage devices](/docs/webapp/devices/), [inspect logs](/docs/webapp/logs/), [configure organization security](/docs/webapp/organization-security/), set up [Enterprise SSO](/docs/webapp/enterprise-sso/) (Enterprise plan), [manage billing](/docs/webapp/settings/) and [manage your account](/docs/webapp/settings/). ## How do I use it? [Section titled “How do I use it?”](#how-do-i-use-it) First, you need to create an account or log in. This is relatively simple and can be done by clicking the `Log in` button in the center of the screen. After you have logged in you will be redirected to the dashboard. This is the main page of the webapp. From here you can navigate to all the other pages. ![login page](/login.webp) ## Creating an account [Section titled “Creating an account”](#creating-an-account) You have to click on the `Create a free account` in the bottom part of the login form. From then it will be as simple as filling a form and following the instructions. ![create account](/create-account.webp) # 2FA Enforcement > Learn how to enforce Two-Factor Authentication (2FA) for all members of your organization to enhance security and protect your apps. Tip This page covers 2FA enforcement in detail. For an overview of all organization security features including password policies and API key controls, see [Organization Security](/docs/webapp/organization-security/). Two-Factor Authentication (2FA) enforcement allows organization administrators to require all members to have 2FA enabled on their accounts before accessing organization resources. This ensures a higher level of security for your apps and data. ## Overview [Section titled “Overview”](#overview) When 2FA enforcement is enabled for an organization: * All members must have 2FA enabled on their Capgo account * Members without 2FA will be denied access to the organization’s apps * Both the web dashboard and CLI will enforce this requirement * New members must enable 2FA before they can access organization resources Tip 2FA enforcement is particularly important for: * Enterprise organizations with strict security policies * Teams handling sensitive user data * Organizations in regulated industries (healthcare, finance, etc.) * Companies requiring SOC 2 or ISO 27001 compliance ## How It Works [Section titled “How It Works”](#how-it-works) ### Web Dashboard [Section titled “Web Dashboard”](#web-dashboard) When you try to access an organization that requires 2FA, and you don’t have it enabled: 1. You’ll see an access denied message 2. You’ll be directed to enable 2FA in your account settings 3. Once enabled, you can access the organization normally ### CLI Access [Section titled “CLI Access”](#cli-access) When using the Capgo CLI to interact with apps in an organization that requires 2FA: ```plaintext 🔐 Access Denied: Two-Factor Authentication Required ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ This organization requires all members to have 2FA enabled. To regain access: 1. Go to https://web.capgo.app/settings/account 2. Enable Two-Factor Authentication on your account 3. Try your command again ``` ## Enabling 2FA Enforcement [Section titled “Enabling 2FA Enforcement”](#enabling-2fa-enforcement) Caution Before enabling 2FA enforcement: * Ensure you have 2FA enabled on your own account * Notify all organization members to enable 2FA * Members without 2FA will immediately lose access ### Via Web Dashboard [Section titled “Via Web Dashboard”](#via-web-dashboard) 1. Navigate to your organization settings 2. Go to the **Security** section 3. Toggle **Require 2FA for all members** 4. Confirm the action ### Via CLI [Section titled “Via CLI”](#via-cli) You can enable 2FA enforcement using the Capgo CLI: ```shell # Enable 2FA enforcement for an organization npx @capgo/cli organization set YOUR_ORG_ID --enforce-2fa # Disable 2FA enforcement npx @capgo/cli organization set YOUR_ORG_ID --no-enforce-2fa ``` When enabling via CLI, you’ll be shown: * Which members don’t have 2FA enabled * A warning if you yourself don’t have 2FA enabled * A confirmation prompt before applying the change ## Checking Member 2FA Status [Section titled “Checking Member 2FA Status”](#checking-member-2fa-status) ### Via CLI [Section titled “Via CLI”](#via-cli-1) You can list all organization members and their 2FA status: ```shell npx @capgo/cli organization members YOUR_ORG_ID ``` This will display: * Member email and role * Whether they have 2FA enabled * A summary of how many members need to enable 2FA ### Via Web Dashboard [Section titled “Via Web Dashboard”](#via-web-dashboard-1) In your organization settings, you can see whether each member has 2FA enabled. ## Setting Up 2FA on Your Account [Section titled “Setting Up 2FA on Your Account”](#setting-up-2fa-on-your-account) If you need to enable 2FA on your account, see our [Two-Factor Authentication setup guide](/docs/webapp/mfa/). ## Best Practices [Section titled “Best Practices”](#best-practices) ### Before Enabling Enforcement [Section titled “Before Enabling Enforcement”](#before-enabling-enforcement) * **Communicate in advance**: Give members at least a week’s notice before enabling enforcement * **Provide support**: Share the [2FA setup guide](/docs/webapp/mfa/) with your team * **Check readiness**: Use `npx @capgo/cli organization members` to see who still needs to enable 2FA ### After Enabling Enforcement [Section titled “After Enabling Enforcement”](#after-enabling-enforcement) * **Monitor access issues**: Be available to help members who get locked out * **Keep backup codes**: Remind members to save their 2FA backup codes * **Review regularly**: Periodically check that all members maintain 2FA ### For CI/CD Pipelines [Section titled “For CI/CD Pipelines”](#for-cicd-pipelines) * **Use API keys**: CI/CD systems should use API keys, not user accounts * **API key owners**: Ensure the user who created CI/CD API keys has 2FA enabled * **Rotate keys**: Regularly rotate API keys used in automated systems ## Troubleshooting [Section titled “Troubleshooting”](#troubleshooting) ### ”Access Denied: Two-Factor Authentication Required” [Section titled “”Access Denied: Two-Factor Authentication Required””](#access-denied-two-factor-authentication-required) **Problem**: You’re seeing this error when trying to access an organization. **Solution**: 1. Go to [Account Settings](https://web.capgo.app/settings/account) 2. Enable 2FA on your account 3. Try accessing the organization again ### ”Cannot enable 2FA enforcement” [Section titled “”Cannot enable 2FA enforcement””](#cannot-enable-2fa-enforcement) **Problem**: You can’t enable 2FA enforcement for your organization. **Solution**: * Ensure you have `super_admin` rights in the organization * Enable 2FA on your own account first * Contact support if the issue persists ### CLI Commands Failing [Section titled “CLI Commands Failing”](#cli-commands-failing) **Problem**: CLI commands fail with 2FA-related errors. **Solution**: * Verify your API key is valid: `npx @capgo/cli doctor` * Ensure the API key owner has 2FA enabled * Re-authenticate if using login-based auth: `npx @capgo/cli login` ## Compliance [Section titled “Compliance”](#compliance) 2FA enforcement helps your organization meet various compliance requirements: | Standard | Requirement | How 2FA Helps | | ------------- | ----------------------- | ---------------------------------------------- | | **SOC 2** | Access controls | Ensures strong authentication for all users | | **ISO 27001** | Information security | Adds a layer of identity verification | | **HIPAA** | Access management | Protects against unauthorized access | | **GDPR** | Data protection | Reduces risk of account compromise | | **PCI DSS** | Authentication controls | Meets multi-factor authentication requirements | ## Next Steps [Section titled “Next Steps”](#next-steps) * [Set up 2FA on your account](/docs/webapp/mfa/) * [Learn about organization management](/docs/webapp/organization-system/) * [Configure API keys for CI/CD](/docs/webapp/api-keys/) # API Keys > How to manage API keys with RBAC role-based permissions in Capgo. Create, edit, regenerate, and delete API keys with fine-grained access control per organization and app. API keys are managed at the organization level with role-based access control (RBAC). Each key can be assigned an organization-wide role and optional per-app roles, giving you fine-grained control over what each key can access. ## Where are API keys managed? [Section titled “Where are API keys managed?”](#where-are-api-keys-managed) Navigate to **Settings > Organization > API Keys** at [console.capgo.app/settings/organization/api-keys](https://console.capgo.app/settings/organization/api-keys). The page displays two sections: * **RBAC Keys** — Keys with assigned roles (recommended). These keys use the new role-based permission system. * **Legacy Keys** — Older keys that use the simple mode-based system (`read`, `upload`, `write`, `all`) without role assignments. ![API keys list page showing RBAC and Legacy sections](/apikeys-org-list.webp) ## How to create a new API key? [Section titled “How to create a new API key?”](#how-to-create-a-new-api-key) 1. Click the **”+”** button at the top of the RBAC keys table. 2. Fill in the **Key information**: * **Name** (required) — A descriptive label for the key (e.g. “CI/CD Deploy”, “Monitoring Read-Only”). * **Create secure key** (optional) — When checked, the key will be hashed server-side. The plain-text key is shown **only once** after creation. You will not be able to retrieve it later. * **Set expiration date** (optional) — Pick a date after which the key will stop working. Some organizations enforce mandatory expiration via policy. ![API key creation form with name, secure key option, and expiration](/apikeys-create-form.webp) 3. Select an **Organization role** — This defines the key’s baseline permissions across the entire organization. Available roles (depending on your own role level): * **None** — No org-wide access; the key only has access to individually assigned apps. * **Member** — Basic read access to the organization. * **Admin** — Full administrative access to the organization (inherits access to all apps). 4. If the selected org role is not Admin, you can add **per-app access**: * Click **”+ Add App”** to open the app picker. * Select one or more apps, then assign a role to each: * **App Reader** — Read-only access to the app. * **App Uploader** — Can upload new bundles. * **App Developer** — Can manage the app configuration and deployments. * **App Admin** — Full access to the app. ![RBAC role selection with org-level and per-app roles](/apikeys-rbac-roles.webp) 5. Click **“Create”**. 6. If you checked “Create secure key”, a modal will display the plain-text key. **Copy it immediately** — it cannot be retrieved after closing the modal. ![One-time API key secret modal with copy button](/apikeys-secret-modal.webp) ## How to manage (edit) an API key? [Section titled “How to manage (edit) an API key?”](#how-to-manage-edit-an-api-key) Click the **wrench icon** (Manage) on any RBAC key in the list. This opens the key detail page where you can: * Change the key **name**. * Update the **organization role**. * Add, remove, or change **per-app roles**. Click **“Save Changes”** when done. ![API key edit page with current role settings](/apikeys-manage.webp) ## How to regenerate an API key? [Section titled “How to regenerate an API key?”](#how-to-regenerate-an-api-key) To regenerate the secret value of an API key, click the **refresh icon** (Regenerate) on any key in the list. A confirmation dialog will appear. After confirming: * For **secure (hashed) keys**: A new plain-text key is generated and displayed once in a modal. Copy it immediately. * For **plain keys**: The key value is regenerated server-side. Any integration using the old key value will stop working immediately. ![API key regeneration confirmation](/apikeys-regenerate-modal.webp) ## How to delete an API key? [Section titled “How to delete an API key?”](#how-to-delete-an-api-key) Click the **trash icon** (Delete) on any key in the list. Confirm the deletion in the dialog. The key is revoked immediately — any request using it will fail. ![API key deletion confirmation dialog](/apikeys-delete-confirm.webp) ## Legacy keys [Section titled “Legacy keys”](#legacy-keys) If you see keys in the **Legacy Keys** section (keys without role assignments), these use the older mode-based permission system (`read`, `upload`, `write`, `all`). They still work but do not benefit from RBAC fine-grained permissions. Legacy keys can be regenerated and deleted from the list, but cannot be edited to add RBAC roles. We recommend creating new RBAC keys and deleting legacy keys when possible. If you need to manage legacy keys directly, you can still access them at [console.capgo.app/dashboard/apikeys](https://console.capgo.app/dashboard/apikeys/). This page is deprecated and will be removed in a future update. # Bundles > Learn how to manage bundles in Capgo. A bundle is a specific version of your application's code and assets. Discover how to view, link to channels, download, and delete bundles. ## Show all bundles [Section titled “Show all bundles”](#show-all-bundles) In Capgo, a bundle represents a specific version of your application’s code and assets, ready to be distributed to devices. First, let’s take a look at the bundles page. You can access it by [clicking on your app](/docs/webapp/main-page) and then [clicking on the bundles tab](/docs/webapp/main-app-page). ![bundle list](/bundles.webp) The bundles list displays: * **Name**: The bundle version number * **Created at**: When the bundle was uploaded * **Channel**: Which channel (if any) the bundle is currently linked to * **Size**: The bundle file size * **Action**: Quick actions including link to channel (gear icon) and delete (trash icon) You can use the **Reload** button to refresh the list, **+ Add** to upload a new bundle, and **Filters** to narrow down the displayed bundles. A search box allows you to find bundles by name. ## Delete a bundle [Section titled “Delete a bundle”](#delete-a-bundle) There are two ways a bundle can be deleted: * Normally * Unsafely The Unsafe way of deleting a bundle was added into Capgo on August 12, 2024. The difference between the two ways is the ability to reuse the version number after the deletion. For example, if you delete a version `1.0.0` the normal way and later try to upload a `1.0.0` version, it will fail. If you delete this version via the unsafe delete, you will be able to upload a `1.0.0` version. Danger Deleting a version unsafely and re-uploading it is REALLY dangerous. It can cause all sorts of bugs and unpredictable behaviour in the plugin. It should NEVER be used for bundles that have been used in a public channel. It is for this reason that deleting a version unsafely requires “super\_admin” privileges ## Managing a specific bundle [Section titled “Managing a specific bundle”](#managing-a-specific-bundle) Once you see the list of all bundles click on the one you want to manage. After you do that you should see something like this: ![bundle info](/bundle-info.webp) The bundle detail page has three tabs: 1. **Information**: Shows all bundle metadata and properties 2. **Dependencies**: Lists the dependencies included in this bundle 3. **History**: Shows the history of changes for this bundle ### Bundle Information [Section titled “Bundle Information”](#bundle-information) The Information tab displays the following details: * **Bundle number**: The version identifier (e.g., 12.87.1) * **ID**: The unique internal identifier for this bundle * **Created at**: When the bundle was first uploaded * **Updated at**: When the bundle was last modified * **Checksum**: The bundle’s integrity hash (click to copy) * **Channel**: The channel this bundle is linked to (click to open channel or change it) * **Encryption**: Whether the bundle is encrypted * **CLI version**: The version of Capgo CLI used to upload this bundle * **Zip app bundle**: The compressed bundle size (click to download) * **Manifest**: The manifest file size * **Status**: Whether the bundle is Active or Inactive (click trash icon to delete) ### Linking a bundle to a channel [Section titled “Linking a bundle to a channel”](#linking-a-bundle-to-a-channel) Click on the gear icon next to the Channel row or in the Action column to open the channel linking modal: ![bundle change](/bundle-change.webp) The modal provides: 1. **Search channel**: Filter available channels by name 2. **Current bundle**: Shows the bundle version being linked 3. **Available channels**: List of all channels with their details (ID, visibility, platforms, creation date). Channels marked as “current” indicate where this bundle is already linked. Public channels show a link icon. 4. **Set bundle to channel**: Confirms the selection and assigns this bundle to the selected channel **Set bundle to channel:** Assigns this bundle as the active version for a chosen channel. Devices subscribed to that channel will then receive this bundle. To open a channel’s dedicated page, click on the channel name link in the Channel row. To unlink a bundle from a channel, navigate to the channel’s configuration page. ### Downloading a bundle [Section titled “Downloading a bundle”](#downloading-a-bundle) To download a bundle, click on the **Zip app bundle** size value in the Information tab. A confirmation dialog will appear, and upon confirmation, the bundle will be downloaded directly to your device. # Channels > Channels are a way to manage your app's updates. Each channel can have one version. This allows you to have multiple versions of your app in production at the same time. ## How Capgo chooses a channel (precedence) [Section titled “How Capgo chooses a channel (precedence)”](#how-capgo-chooses-a-channel-precedence) When a device asks Capgo for an update, the channel it will use is decided in the following order (highest priority first): 1. **Forced device mapping**: If the device ID is explicitly forced to a channel (see the *Forced devices* list inside the channel settings), that channel always wins. 2. **Cloud override (created by `setChannel()` or Webapp action)**: Calling [`setChannel`](/docs/plugin/api/#setchannel) (or changing a device’s channel in the dashboard) writes a persistent override in the cloud tied to that device ID. That override is consulted after forced mapping but before any defaults. Re‑installing the app does **not** clear it; deleting the device entry does. 3. **Capacitor config `defaultChannel` (test build default)**: For internal / beta / test builds you can set `defaultChannel` (legacy key `channel`) in `capacitor.config.*` so test devices start on a pre-release channel (e.g. `beta`, `pr-123`). If absent, the device will proceed to the cloud default. Production builds usually leave this unset. 4. **Cloud Default Channel (primary strategy for \~99% of users)**: The main production channel virtually all real users land on. Any new device without a force, without an override, and without a config `defaultChannel` uses this. Changing it rolls out (or rolls back) for everyone in seconds—no new binary. Why the **cloud default** is the main path: * Instant rollout or rollback without rebuilding or re‑publishing native binaries. * One place to manage iOS, Android, and Electron behavior. * Safer: you can confirm bundles exist and settings are correct before switching default. * Auditable changes (team members can see who changed what in the UI / logs). Design principle: Layers above (force / override / config) are *exceptions* (debug single user, QA switching, test build defaults). Normal users flow to the cloud default. Changing the *cloud default* channel affects *new* normal devices that: * Are not forced * Do not already have a cloud override * Do not have an app-level `defaultChannel` defined If a test build ships with `defaultChannel: 'beta'` and you later change the cloud default to `production`, devices that started on `beta` via the config stay there until you: (a) override them with `setChannel()`, (b) force them, or (c) delete the device entry. Devices stay on their current channel unless you: * Force them to another channel. * Call `setChannel()` (creating/replacing the cloud override) or change it manually in the dashboard. * Remove / archive the channel they are on (then they will fall back through the precedence again at next check). If a channel is disabled for a platform (see iOS / Android / Electron toggles) and would otherwise have been selected, the selection skips it and falls back to the next rule. > Note: Setting `defaultChannel` means changing it requires a new binary; use it intentionally for test/QA, not for general production control. ### Capacitor config example [Section titled “Capacitor config example”](#capacitor-config-example) capacitor.config.ts ```ts // Example: a TestFlight or internal QA build defaults to the beta channel. const config = { plugins: { Capgo: { defaultChannel: 'beta', // Test build default. Omit in production so users attach to cloud default. // legacy key: channel }, }, }; export default config; ``` If you later change the dashboard default to `production`, devices already on another channel (via config, override, or force) will NOT move automatically; only fresh devices (or those whose override/force you clear) pick it up. *** ## Managing channels [Section titled “Managing channels”](#managing-channels) First, let’s take a look at the channels page. You can access it by [clicking on your app](/docs/webapp/main-page) and then [clicking on the channels tab](/docs/webapp/main-app-page). ![channel list](/channels.webp) ## Creating a channel [Section titled “Creating a channel”](#creating-a-channel) As you can see, there exists a plus button in the lower right corner. (`1` in the image) Clicking on it will open a modal where you can create a new channel. ![new channel](/new_channel_modal.webp) Then after you click on `Add` a new channel should appear in the list. ![after channel create](/post-channel-create.webp) ## What does misconfigured mean? [Section titled “What does misconfigured mean?”](#what-does-misconfigured-mean) Sometimes the configuration of a channel is not valid. In that case, you will get a big warning and the `Misconfigured` column will say `Yes` for one or more of the channels. You can learn more about it [here](/docs/cli/commands/#disable-updates-strategy) ## Deleting a channel [Section titled “Deleting a channel”](#deleting-a-channel) Deleting a channel is straight forward. Just click on the trash icon and confirm the deletion. (`2` in the image) ## Managing a channel [Section titled “Managing a channel”](#managing-a-channel) Clicking on the channel name will open a modal where you can manage the channel settings. (`3` in the image) ![Channel settings](/channel_settings.webp) The channel settings page contains all the configuration options for your channel. Let’s go through each setting. *** First the `Default channel` toggle. When enabled, this channel becomes the default for new devices. For a comprehensive explanation of how default channels work, including how to set up platform-specific defaults (one for iOS, one for Android, and one for Electron), see the [Default Channel Configuration](/docs/webapp/main-app-page/#default-channel-configuration) section. *** Second the `IOS` setting. This is relatively simple. If this is false then IOS devices will not be allowed to download updates from this channel. Third is the `Android` setting. This is similar to `IOS`. If this is false then Android devices will not be allowed to download updates from this channel. Fourth is the `Electron` setting. This is similar to `IOS` and `Android`. If this is false then Electron apps will not be allowed to download updates from this channel. Fifth is the `Disable auto downgrade under native` setting. If this is true then it will be impossible to downgrade from a native version. This means that if you have uploaded a `1.2.0` version to the app store or play store and try to set the channel version to `1.1.0` then the update (downgrade) will fail. Sixth is the `Disable auto update`. This setting is quite complex, and you can learn more about it [here](/docs/cli/commands/#disable-updates-strategy) As for `Allow development build`. If this is true then development builds will be allowed to download updates from this channel. If not then any update request that has the `prod` set to false will be rejected. This is mostly useful for testing purposes. Seventh is the `Allow Emulators`. If this is false then Capgo will disallow any update request that comes from an emulator. This is mostly useful for testing purposes. Eight is the `Allow devices to self associate`. If this is true then the [setChannel](/docs/plugin/api/#setchannel) method will be available. If this is set to false and you try to call the [setChannel](/docs/plugin/api/#setchannel) method with this channel then the call will fail. # Devices > A comprehensive guide on utilizing the devices page to manage and configure your devices effectively, including filtering options and detailed configuration settings for individual devices. Data Retention Device data is retained for **90 days** from the last device activity. Devices that haven’t connected to Capgo within this period will be automatically removed from the list. Active devices are continuously tracked as they check for updates. ## Show the list of all devices [Section titled “Show the list of all devices”](#show-the-list-of-all-devices) First, let’s take a look at the devices page. You can access it by [clicking on your app](/docs/webapp/main-page) and then [clicking on the devices tab](/docs/webapp/main-app-page). ![devices list](/devices.webp) 1. **Devices tab** - Click this tab in the navigation bar to access the devices page 2. **Filters** - Click to filter devices by: * **Override** - Show only devices that have a [custom channel](/docs/plugin/api/#setchannel) or a custom version * **Custom ID** - Show only devices with a custom identifier set ## Configuring a device [Section titled “Configuring a device”](#configuring-a-device) To configure a specific device click on it in the table and then you should see something like this: ![show one device](/device-specific.webp) 1. **Information** - View device details including Device ID, Last update, Platform, Plugin version, Version, Version builtin, OS version, and whether it’s a Production app 2. **Deployments** - View the deployment history for this device 3. **Logs** - View logs associated with this device 4. **Channel override** - Override the channel for this specific device. If set, this device will not use the public (default) channel and will only receive updates from the selected channel ### Custom ID [Section titled “Custom ID”](#custom-id) The `Custom ID` is a very useful field that helps you connect the device to an ID you can recognize for your own users. Use it to easily identify which device belongs to which user. Custom ID can only be set from the device itself using `CapacitorUpdater.setCustomId({ customId: user });` # SSO (Enterprise) > Set up SAML 2.0 single sign-on (SSO) for your Capgo organization: prerequisites, IdP configuration, DNS domain verification, provider lifecycle, and enforcement. Caution **SSO setup is available on the Enterprise plan only.** If you do not see **SSO configuration** under **Settings → Organization → Security**, ensure your organization is on the Enterprise plan or contact your Capgo account contact. ## What is SSO? [Section titled “What is SSO?”](#what-is-sso) Single Sign-On (SSO) lets your team log in to Capgo using your company identity provider (IdP). Capgo uses SAML 2.0 through Supabase Auth. When a user’s email domain matches an active SSO provider, they can authenticate against your IdP and are provisioned into the organization during the SSO callback. SSO does not change what users can do. Permissions are controlled by [organization roles](/docs/webapp/organization-system/#roles-overview). SSO only changes how they authenticate. ## Prerequisites [Section titled “Prerequisites”](#prerequisites) Before starting: * Enterprise subscription active on the Capgo organization. * An identity provider that supports **SAML 2.0** and exposes an IdP **metadata URL** (HTTPS). * Ability to publish a **DNS TXT record** for the email domain (e.g. `company.com` for users logging in as `user@company.com`). * A Capgo organization member with permission to update organization settings. * An **IdP admin** contact on your IT/security side. ## Where to find SSO settings [Section titled “Where to find SSO settings”](#where-to-find-sso-settings) 1. Open <https://console.capgo.app/> 2. Click **Settings** in the left sidebar 3. Select the **Organization** tab 4. Select the **Security** tab 5. Scroll to **SSO configuration**. The form is available only when the org is on the Enterprise plan. ## Step 1 - Configure your IdP [Section titled “Step 1 - Configure your IdP”](#step-1---configure-your-idp) In your identity provider, create a new SAML 2.0 application. You will need the following **Service Provider** values shown in the Capgo SSO configuration panel: | Field | Where to use it | | ------------------- | --------------------------------------------------------------- | | **ACS URL** | Assertion Consumer Service URL in your IdP SAML app | | **Entity ID** | Service Provider entity identifier | | **SP metadata URL** | Optional: import if your IdP supports SP metadata import by URL | | **NameID format** | Format expected for the SAML Name Identifier | Your IdP must release the user’s **email address** in the assertion. Capgo uses the email domain to resolve the active SSO provider and to match existing accounts. ## Step 2 - Add the SSO provider in Capgo [Section titled “Step 2 - Add the SSO provider in Capgo”](#step-2---add-the-sso-provider-in-capgo) 1. In the SSO configuration panel, click to add a new provider 2. Enter the **email domain** (e.g. `company.com`). It must match the domain part of your users’ sign-in emails 3. Enter your IdP **metadata URL** (HTTPS) 4. Submit The provider is created with status **Pending verification**. ## Step 3 - DNS domain verification [Section titled “Step 3 - DNS domain verification”](#step-3---dns-domain-verification) Capgo verifies you control the domain before SSO can become active. Add a **TXT** record at your DNS provider: | Field | Value | | ----------- | ---------------------------------------------------------- | | Type | `TXT` | | Name / host | `_capgo-sso.<your-domain>` (e.g. `_capgo-sso.company.com`) | | Value | The verification token shown in the dashboard panel | Once the record is published (DNS TTL propagation typically takes a few minutes to an hour), click **Verify DNS** in the dashboard. On success, the provider moves to **Verified**. ## Step 4 - Activate the provider [Section titled “Step 4 - Activate the provider”](#step-4---activate-the-provider) After DNS verification, click **Activate**. The provider status becomes **Active**. Only **Active** providers are used during the SSO login flow. You can choose **Deactivate** in the dashboard at any time. That moves the provider to **Disabled**, which pauses SSO for that domain without deleting the configuration. ## Step 5 - Test and assign roles [Section titled “Step 5 - Test and assign roles”](#step-5---test-and-assign-roles) When a user signs in via SSO for the first time and has no existing membership in that organization, Capgo provisions them with the **read** role. After pilot users sign in: 1. Go to **Settings → Organization → Members** 2. Find each SSO-provisioned user 3. Adjust their role to the appropriate level (**Upload**, **Write**, **Admin**, etc.) See the [full permission breakdown](/docs/webapp/organization-roles/) for what each role can do. Note If Supabase creates a separate SSO auth user for an email that already exists in Capgo, Capgo merges the SSO identity into the existing account and asks the user to sign in again. ## Optional - Enforce SSO [Section titled “Optional - Enforce SSO”](#optional---enforce-sso) On an **Active** provider you can toggle **Enforce SSO**. When enabled, Capgo marks existing auth users for that email domain as SSO-only and the login flow requires IdP authentication for that domain. Setting the provider to **Disabled** (**Deactivate**) or turning enforcement off removes that SSO-only flag for the domain. Caution Coordinate with your IdP admin and notify all affected users before enabling enforcement. Users who cannot complete IdP authentication will not be able to sign in with their password for that domain. ## Provider status reference [Section titled “Provider status reference”](#provider-status-reference) | Status | Meaning | | ------------------------ | ----------------------------------------------------------------------------------------------------------------- | | **Pending verification** | DNS TXT record not yet verified | | **Verified** | Domain ownership confirmed; ready to activate | | **Active** | SSO is live for this domain | | **Disabled** | Set by **Deactivate** in the dashboard; SSO not used for that domain; use **Re-activate** to return to **Active** | ## Rollout checklist [Section titled “Rollout checklist”](#rollout-checklist) * [ ] Enterprise plan confirmed * [ ] SAML app created in IdP with ACS URL and Entity ID from Capgo * [ ] IdP configured to release a stable email claim * [ ] DNS TXT record published and **Verify DNS** succeeded * [ ] Provider activated * [ ] Pilot users signed in successfully * [ ] Roles elevated from default **read** as needed * [ ] Enforcement decision made (and communicated if enabled) ## Related documentation [Section titled “Related documentation”](#related-documentation) * [Organization: roles and permissions](/docs/webapp/organization-system/) * [Organization security: 2FA, passwords, API keys](/docs/webapp/organization-security/) # Logs > Understand and utilize the application logs of Capgo to diagnostics and track the action of your devices with the updates. ## Understanding Application Logs [Section titled “Understanding Application Logs”](#understanding-application-logs) The Logs page provides a detailed history of update events and diagnostic information for your application. This is crucial for monitoring the update process, troubleshooting issues, and understanding how your devices interact with Capgo. You can access it by [clicking on your app](/docs/webapp/main-page) and then [clicking on the “Logs” tab (previously named “updates” in some older screenshots or documentation)](/docs/webapp/main-app-page). From there you should see a page similar to this, displaying a list of log entries: ![Logs page overview showing the main interface](/logs.webp) Logs Page Overview The logs page interface includes: 1. **Logs Tab** - The navigation tab to access the logs view 2. **Reload Button** - Refresh the logs list with the latest data 3. **Time Range & Actions Filters** - Filter logs by date range and action type (see sections below) Each row shows: * **Timestamp** (UTC) * **Device ID** * **Action code** (what happened) * **Version name** (bundle or `builtin`) Click a row to jump to the device detail page for the full history. ### Filtering by Date Range [Section titled “Filtering by Date Range”](#filtering-by-date-range) You can filter logs by a specific time period using the date picker: ![Date range picker for filtering logs](/logs_date_range.webp) Date Range Filter 1. **Quick Presets** - Select common time ranges: Last 1h, 3h, 6h, or 12h 2. **Start Time** - Set a custom start time for the range 3. **End Time** - Set a custom end time for the range 4. **Calendar** - Pick specific dates using the calendar view Click “Select” to apply your chosen date range, or “Cancel” to dismiss the picker. ### Filtering by Action Type [Section titled “Filtering by Action Type”](#filtering-by-action-type) The Actions dropdown lets you filter logs by specific event types: ![Actions filter dropdown for filtering logs by event type](/logs_filters.webp) Actions Filter Available action filters include: * **Device heartbeat** - Periodic health checks from devices * **Version deletion requested** - When a bundle version is deleted * **Reset to default version** - When a device reverts to the builtin bundle * **Version installed successfully** - Successful bundle installation * **New version sent to device** - When Capgo sends an update to a device * **Version installation failed** - When bundle installation fails Use the search box at the top to quickly find specific action types. You can select multiple actions to show logs matching any of the selected types. ### Sample log snippet (fake data) [Section titled “Sample log snippet (fake data)”](#sample-log-snippet-fake-data) | Time (UTC) | Device ID | Action | Version | What it tells you | | ------------------- | --------- | -------------------------- | ------- | --------------------------------------------------------- | | 2025-01-14 10:00:01 | `A1B2C3` | `get` | 2.4.1 | Device asked Capgo if an update is available | | 2025-01-14 10:00:03 | `A1B2C3` | `download_manifest_start` | 2.4.1 | Manifest fetch kicked off; SDK is about to download files | | 2025-01-14 10:00:07 | `A1B2C3` | `download_40` | 2.4.1 | Bundle download is 40% complete | | 2025-01-14 10:00:12 | `A1B2C3` | `download_zip_complete` | 2.4.1 | Zip finished downloading | | 2025-01-14 10:00:13 | `A1B2C3` | `set` | 2.4.1 | Bundle installed and marked as next to run | | 2025-01-14 10:05:00 | `B9C8D7` | `disableAutoUpdateToMajor` | 1.9.0 | Channel policy blocked a jump to 2.x | | 2025-01-14 10:05:05 | `B9C8D7` | `rateLimited` | builtin | Device hit the request limit; SDK backs off until restart | ## Example Log Scenarios [Section titled “Example Log Scenarios”](#example-log-scenarios) To help you understand what the logs tell you, here are example sequences showing real device update journeys: ### Successful Update Flow [Section titled “Successful Update Flow”](#successful-update-flow) This is what a healthy update looks like in your logs: | Time | Device ID | Action | Version | What it means | | -------- | ---------- | ------------------- | ------- | ---------------------------------------------------------- | | 10:00:01 | `a1b2c3d4` | `get` | 1.2.0 | Device checked for updates and received version 1.2.0 info | | 10:00:02 | `a1b2c3d4` | `download_10` | 1.2.0 | Download started, 10% complete | | 10:00:03 | `a1b2c3d4` | `download_50` | 1.2.0 | Download at 50% | | 10:00:05 | `a1b2c3d4` | `download_complete` | 1.2.0 | Download finished successfully | | 10:00:06 | `a1b2c3d4` | `set` | 1.2.0 | Bundle installed and activated | ### Device Already Up-to-Date [Section titled “Device Already Up-to-Date”](#device-already-up-to-date) When a device checks but already has the latest version: | Time | Device ID | Action | Version | What it means | | -------- | ---------- | ------- | ------- | --------------------------------------------------------- | | 14:30:00 | `e5f6g7h8` | `noNew` | 1.2.0 | Device is already on the latest version, no update needed | ### Failed Update with Rollback [Section titled “Failed Update with Rollback”](#failed-update-with-rollback) When an update fails and the device rolls back: | Time | Device ID | Action | Version | What it means | | -------- | ---------- | ------------------- | ------- | -------------------------------------------------------------------- | | 11:15:00 | `i9j0k1l2` | `get` | 1.3.0 | Device received update info | | 11:15:02 | `i9j0k1l2` | `download_complete` | 1.3.0 | Download completed | | 11:15:03 | `i9j0k1l2` | `set` | 1.3.0 | Bundle was set | | 11:15:10 | `i9j0k1l2` | `update_fail` | 1.3.0 | App crashed or `notifyAppReady()` wasn’t called - rollback triggered | | 11:15:11 | `i9j0k1l2` | `reset` | builtin | Device reverted to the built-in version | **Action needed**: Check that your app calls `notifyAppReady()` after successful initialization. See [the plugin documentation](/docs/plugin/api/#notifyappready) for details. ### Download Failure [Section titled “Download Failure”](#download-failure) When network issues prevent the download: | Time | Device ID | Action | Version | What it means | | -------- | ---------- | --------------- | ------- | -------------------------------------------------------- | | 09:45:00 | `m3n4o5p6` | `get` | 1.2.0 | Device received update info | | 09:45:01 | `m3n4o5p6` | `download_30` | 1.2.0 | Download started but… | | 09:45:15 | `m3n4o5p6` | `download_fail` | 1.2.0 | Download failed (network timeout, connection lost, etc.) | **Action needed**: The device will retry automatically on next app launch. No action required unless this happens frequently. ### Plan Limit Reached [Section titled “Plan Limit Reached”](#plan-limit-reached) When your account reaches its device limit: | Time | Device ID | Action | Version | What it means | | -------- | ---------- | ----------------- | ------- | ------------------------------------------------------------------------------- | | 16:00:00 | `q7r8s9t0` | `needPlanUpgrade` | - | This device won’t receive updates until you upgrade or the billing cycle resets | **Action needed**: [Upgrade your plan](/docs/webapp/settings/) or wait for the next billing cycle. ### Channel Configuration Blocking Updates [Section titled “Channel Configuration Blocking Updates”](#channel-configuration-blocking-updates) When channel settings prevent an update: | Time | Device ID | Action | Version | What it means | | -------- | ---------- | -------------------------- | ------- | --------------------------------------------------------------------- | | 12:00:00 | `u1v2w3x4` | `disableAutoUpdateToMajor` | 2.0.0 | Device on v1.x can’t auto-update to v2.x (major version jump blocked) | | 12:05:00 | `y5z6a7b8` | `disableEmulator` | 1.2.0 | Emulator detected, and channel blocks emulators | | 12:10:00 | `c9d0e1f2` | `disableDevBuild` | 1.2.0 | Dev build detected, and channel blocks dev builds | **Action needed**: These are intentional protections. If you want to allow these updates, modify your [channel settings](/docs/webapp/channels/). ## Log codes (Capgo backend enum) [Section titled “Log codes (Capgo backend enum)”](#log-codes-capgo-backend-enum) These codes come from the `stats_action` enum used by the dashboard API (`capgo/src/types/supabase.types.ts`). If you see a new code in the UI, it was emitted by the SDK or backend and validated against this list. **Happy path & lifecycle** | Code(s) | Meaning | | ------------------------------------------------------- | -------------------------------------------------------------------- | | `get` | Device asked Capgo for the current channel manifest | | `download_manifest_start`, `download_manifest_complete` | Manifest download began / finished (for delta or multi-file bundles) | | `download_zip_start`, `download_zip_complete` | Zip archive download began / finished | | `download_10` … `download_90` | Download progress milestones | | `download_complete` | Entire bundle downloaded | | `set` | Bundle staged for next launch | | `reset` | Device reverted to the builtin bundle | | `delete` | Bundle removed from local storage | | `uninstall` | App uninstall detected | | `app_moved_to_foreground`, `app_moved_to_background` | App lifecycle events recorded by SDK | | `ping` | Health/heartbeat check from device | | `setChannel`, `getChannel` | Channel overridden or fetched via SDK call | **Configuration or policy blocks** | Code(s) | Why the update was blocked | | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------- | | `disableAutoUpdate`, `disableAutoUpdateToMajor`, `disableAutoUpdateToMinor`, `disableAutoUpdateToPatch`, `disableAutoUpdateMetadata`, `disableAutoUpdateUnderNative` | Channel strategy forbids this semver jump | | `disablePlatformIos`, `disablePlatformAndroid` | Platform is disabled on the channel | | `disableDevBuild`, `disableEmulator` | Dev builds or emulators not allowed | | `cannotUpdateViaPrivateChannel`, `NoChannelOrOverride`, `channelMisconfigured` | Channel selection or override failed | | `missingBundle`, `cannotGetBundle` | Manifest refers to a bundle Capgo cannot serve | | `needPlanUpgrade` | Org hit its plan/device limit | | `rateLimited` | Too many requests; SDK throttles until restart | | `blocked_by_server_url`, `backend_refusal`, `InvalidIp` | Server-side rule blocked the request | **Download / integrity / install failures** | Code(s) | Meaning | | ------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | | `download_fail` | Bundle download failed (network or response error) | | `download_manifest_file_fail`, `download_manifest_checksum_fail`, `download_manifest_brotli_fail` | Manifest file couldn’t be retrieved or validated | | `checksum_fail`, `checksum_required` | Integrity check failed or checksum missing | | `unzip_fail`, `directory_path_fail`, `canonical_path_fail`, `windows_path_fail` | File system or unzip validation failed | | `decrypt_fail` | Decryption failed (encrypted bundle) | | `update_fail` | Bundle installed but app never called `notifyAppReady()`; rollback triggered | | `download_zip_*` with no subsequent `set` | Download finished but install phase never completed | ➡️ Need deeper per-code guidance? See **[Full Log Code Reference and Debugging Guide](/docs/plugins/updater/debugging/#understanding-cloud-logs)**. ## Getting More Details About a Log [Section titled “Getting More Details About a Log”](#getting-more-details-about-a-log) If you click on a specific log entry, it will typically take you to the [device’s page](/docs/webapp/devices/). This allows you to see the full history for that particular device, which can be very helpful for diagnosing device-specific issues or understanding its update journey. # App Page > What does the app page of the Capgo webapp shows? And what you can do with it. ## What does the app page shows? [Section titled “What does the app page shows?”](#what-does-the-app-page-shows) First, let’s take a look at the main page of the app: In Capgo, an app represents your mobile application integrated with Capgo’s live update system. It allows you to manage updates, channels, and devices seamlessly. ![Main page screenshot](/main-app-page.webp) Let’s take a closer look at this. The main app page is divided into several key areas: 1. **Top Navigation Bar:** Provides access to different sections of your app management: * **Dashboard (1):** The current view, displaying key metrics and summaries. * **Information (2):** Displays your app’s core settings and details (see “App Information” section below). * **[Bundles (3)](/docs/webapp/bundles/):** Manage your app’s versions and releases. * **[Channels (4)](/docs/webapp/channels/):** Configure and manage different update channels (e.g., production, beta). * **[Devices (5)](/docs/webapp/devices/):** View and manage registered devices, including setting specific overrides. * **[Logs (6)](/docs/webapp/logs/):** Access detailed logs and error reports for your app. * **Builds (7):** View and manage your app builds. 2. **Statistics Display:** Visualizes important metrics for the last billing period (data reflects usage from your billing day, not the 1st of the month): * **Monthly Active Users (8):** Tracks the number of unique active users over time. * **Storage (9):** Shows the current storage consumption. * **Bandwidth (10):** Displays the bandwidth usage. * **Active Bundle (11):** Shows the distribution of active devices across different app bundles. 3. **Summary Cards:** Offers a quick overview of key counts: * **Bundle Uploads (12):** Total number of app bundles uploaded. * **Updates Statistics (13):** Total number of updates performed, including requests, installs, and failures. * **Deployment Statistics (14):** Total number of deployments. 4. **Display Options (15-18):** Controls for filtering and viewing the statistics: * **Daily (15):** View statistics on a daily basis. * **Cumulative (16):** View cumulative statistics over time. * **Billing Period (17):** View statistics for the current billing period. * **Date Range (18):** Select a custom date range (e.g., last 30 days). ## App Information [Section titled “App Information”](#app-information) This section corresponds to the “Information” tab (1) in the top navigation bar. Here you can view and manage crucial details and settings for your application. ![App Information Page](/app_info.webp) App Information Page Here’s a breakdown of the available fields and actions: * **App Icon (2):** Displays your application’s icon. You can click the “Change” button to upload a new icon. * **App ID (3):** A unique identifier for your application within Capgo. This ID is not editable. * **App Name (4):** The display name for your application. You can modify this as needed. * **Default Upload Channel (5):** Specifies the default channel to which new bundles will be uploaded. You can click the edit icon to select a different default channel. * **Default Download Channel (6):** Specifies the default channel from which devices will download updates. You can click the edit icon to select a different default channel. See the [Default Channel Configuration](#default-channel-configuration) section below for detailed information. * **Auto Delete Bundles Not Used (after x seconds) (7):** This setting allows you to automatically delete old bundles that haven’t been used for a specified duration (in seconds). Set to `0` to disable auto-deletion. This helps manage storage and keep your bundle list clean. * **Expose Bundle Metadata to Plugin (8):** When enabled, bundle link and comment fields will be sent to the Capacitor Updater plugin. This feature requires plugin version 7.35.0 or higher. * **Transfer App Ownership (9):** This section provides an option to initiate the transfer of your application to a different organization you are a part of. * **Delete App Button:** Permanently deletes your application from Capgo. This action is irreversible and will remove all associated data, bundles, channels, and devices. * **Update Button:** Saves any changes you’ve made to the editable fields on this page (e.g., App Name, Default Upload Channel, Auto Delete Bundles setting). ## Default Channel Configuration [Section titled “Default Channel Configuration”](#default-channel-configuration) The **Default Download Channel** is one of the most important settings for your app. It determines which channel new devices will receive updates from when they first connect to Capgo. ### How Default Channels Work [Section titled “How Default Channels Work”](#how-default-channels-work) When a device requests an update from Capgo, the system determines which channel to use based on the following precedence (highest priority first): 1. **Forced device mapping**: If the device ID is explicitly forced to a channel in the channel settings, that channel always wins. 2. **Cloud override**: If the device has been assigned to a channel via `setChannel()` or manually in the dashboard, that override is used. 3. **Capacitor config `defaultChannel`**: If set in your `capacitor.config.*` file, this is used for test/beta builds. 4. **Default Download Channel**: The setting configured here—this is what \~99% of your production users will use. ### Platform-Specific Default Channels [Section titled “Platform-Specific Default Channels”](#platform-specific-default-channels) You can configure platform-specific default channels—for example one for iOS, one for Android, and one for Electron. This is useful when: * You want to roll out updates to one platform before the other * You need different update strategies per platform * You’re testing a new version on one platform while keeping the other stable To set up platform-specific defaults: 1. Create separate channels for each platform (for example `production-ios`, `production-android`, and `production-electron`) 2. In each channel’s settings, enable only the relevant platform (iOS, Android, or Electron toggle) 3. Mark both channels as “Default” - Capgo allows this when channels target different platforms When a device requests an update: * iOS devices will receive updates from the iOS-enabled default channel * Android devices will receive updates from the Android-enabled default channel ### Single Default Channel (Recommended for Most Apps) [Section titled “Single Default Channel (Recommended for Most Apps)”](#single-default-channel-recommended-for-most-apps) For most applications, a single default channel that supports all three core platforms is the simplest approach: 1. Create one channel (e.g., `production`) 2. Ensure iOS, Android, and Electron toggles are enabled 3. Mark it as the default channel This ensures consistent behavior across all platforms and simplifies your release workflow. ### Changing the Default Channel [Section titled “Changing the Default Channel”](#changing-the-default-channel) When you change the default channel: * **New devices** will immediately start receiving updates from the new default * **Existing devices** that already have a channel assignment (via override or force) will NOT automatically switch * To move existing devices, you need to either: * Use `setChannel()` to override them programmatically * Force them to the new channel in the dashboard * Delete their device entries (they’ll re-register with the new default) > **Tip**: Always test your new default channel with a small group of forced devices before making it the default for all users. # Home > What does the home page of the Capgo webapp shows? And what you can do with it. ## What does the main page shows? [Section titled “What does the main page shows?”](#what-does-the-main-page-shows) First, let’s take a look at the main page: ![Main page screenshot](/main-page.webp) Let’s start at the beginning. The first thing you see is the **stats**. It contains app-specific statistics. Those updates depend on the usage of the app The second thing you see is the list of all available apps. This will change depending on how many apps have you created. You can click on each app to see more details about it. The third thing you see is the **API keys** button. This button will take you to the [API keys](/docs/webapp/api-keys/) page. The next thing you see is the **your name and picture** button. This button will change depending on your first and second name and it will take you to the [settings](/docs/webapp/settings/) or support page. # Two-factor authentication > Managing two-factor authentication to better protect your capgo account. This doc will help you to make your account the most secure possible, and prevent bad actor sending unwanted bundle to your user ## What is 2FA? [Section titled “What is 2FA?”](#what-is-2fa) 2FA is a security measure designed to prevent a bad actor from taking over your capgo account.\ It achieves it by requiring an additional code. This code is stored on your mobile phone or a hardware 2FA key. It changes every 30 seconds, making it impossible to guess ## Requirements for this guide [Section titled “Requirements for this guide”](#requirements-for-this-guide) * An Android or IOS phone * Internet connection ## What will this guide cover? [Section titled “What will this guide cover?”](#what-will-this-guide-cover) This guide will show how to setup 2FA using `Google Authenticator`. Other apps exist to serve a similar purpose, however I cannot cover the entire topic of 2FA in this guide. ## How to setup 2FA? [Section titled “How to setup 2FA?”](#how-to-setup-2fa) First download the `Google Authenticator` app. If you are on Android,, you can download it from the [play store](https://play.google.com/store/apps/details/?id=com.google.android.apps.authenticator2). On IOS you can download it from the [App store](https://apps.apple.com/us/app/google-authenticator/id388497605/) Second, please go to [capgo’s account settings](https://console.capgo.app/dashboard/settings/account/). There you should see a green button that should look like this ![Button MFA](/button-mfa.webp) Click it, and once you do, a QR code should appear ![Enable MFA](/enable-mfa.webp) Danger ⚠️ Important Note:\ Never share this QR code with anyone, or you could get logged out of your account Next, please open the `Google Authenticator` on your phone. Once you do, follow these steps: Click the plus button ![MFA auth plus](/mfa-auth-plus.webp) After that, please click the camera button ![MFA scan QR](/mfa-scan-qr.webp) That will open the camera preview. Please scan the QR code shown on your PC. After you do that, you should see something like this: ![MFA final code](/mfa-final-code.webp) Then please go back to the PC and click the verify button ![Verify MFA](/enable-mfa-verify.webp) This will open a window to type our 2FA code. In my case, this code is `095101` but it will be different for you.\ After you type this code, please click on the `verify` button ![MFA verify code final](/mfa-verify-final-code.webp) If you entered the correct code and pressed `verify` you should see a pop-up like this ![MFA enabled](/mfa-enabled.webp) Congrats!\ You enabled 2FA authentication 🎉 ## How to login using 2FA [Section titled “How to login using 2FA”](#how-to-login-using-2fa) Next time you login to your account, you will see a window like this ![MFA required](/mfa-required.webp) Please open the authenticator and copy your auth code ![MFA login](/mfa-login.webp) Danger ⚠️ Important Note:\ Press `verify` before the code refresh, otherwise the code will change, and the old one will no longer be valid Then input the code, into the login form and pres the `verify` ![MFA login](/mfa-final-login-verify.webp) If you entered the correct code you should see the capgo dashboard ## How to disable 2FA [Section titled “How to disable 2FA”](#how-to-disable-2fa) To disable 2FA please go to the [capgo’s account settings](https://console.capgo.app/dashboard/settings/account/). There you should see a red button that should look like this: ![MFA disable button](/mfa-disable-button.webp) Click it, and and you should see a screen like this ![MFA disabled](/mfa-disable-2.webp) Just press the `disable` button, and that’s it. # Access Control Reference > Complete reference for Capgo's role-based access control system — every role, every permission, the hierarchy, and how to assign roles via API and CLI. Capgo uses **role-based access control (RBAC)** to manage what each team member can do. Roles are organized by **scope** — from the entire organization down to a single bundle. For a visual walkthrough of managing members in the dashboard, see [Organization](/docs/webapp/organization-system/). *** ## Role scopes [Section titled “Role scopes”](#role-scopes) Every role belongs to a scope that determines what resource it grants access to. | Scope | Applies to | Example use case | | ---------------- | ------------------------------- | ---------------------------------------------------------------------- | | **Organization** | The entire org and all its apps | Your co-founder gets Super Admin; your accountant gets Billing Manager | | **App** | A single app and its channels | A contractor working on one app gets App Developer | | **Channel** | A single channel within an app | A QA engineer only manages the `staging` channel | | **Bundle** | A single bundle version | A reviewer needs read access to one specific release | A member can hold **one role per scope target** — for example, one org role, one role on App A, and a different role on App B. *** ## Organization roles [Section titled “Organization roles”](#organization-roles) These roles are assigned when inviting a member. They grant access across the entire organization. | Role | Internal name | Description | | ------------------- | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | | **Super Admin** | `org_super_admin` | Owner-equivalent. Full control including deleting the org, managing billing, and transferring apps. Automatically granted to the org creator. | | **Admin** | `org_admin` | Full administration — manage members, apps, channels. Cannot delete the org, update billing, transfer apps, or promote users to Super Admin. | | **Billing Manager** | `org_billing_admin` | Billing-only access: view and update billing info, invoices, and billing audit logs. No access to apps or members. | | **Member** | `org_member` | Read-only access to the org and all its apps. | ### Organization permission matrix [Section titled “Organization permission matrix”](#organization-permission-matrix) | Permission | Description | Super Admin | Admin | Billing Manager | Member | | ------------------------ | ------------------------------------------------------------------------------------- | :---------: | :---: | :-------------: | :----: | | `org.read` | View the organization | ✅ | ✅ | ✅ | ✅ | | `org.update_settings` | Edit org name, logo, management email | ✅ | ✅ | ❌ | ❌ | | `org.delete` | Permanently delete the organization | ✅ | ❌ | ❌ | ❌ | | `org.read_members` | View the member list | ✅ | ✅ | ❌ | ✅ | | `org.invite_user` | Invite new members | ✅ | ✅ | ❌ | ❌ | | `org.update_user_roles` | Change member roles (Admin cannot promote to Super Admin — blocked by role hierarchy) | ✅ | ✅ | ❌ | ❌ | | `org.read_billing` | View billing info and current plan | ✅ | ✅ | ✅ | ❌ | | `org.update_billing` | Update payment method and plan | ✅ | ❌ | ✅ | ❌ | | `org.read_invoices` | View invoices | ✅ | ✅ | ✅ | ❌ | | `org.read_audit` | View organization activity log | ✅ | ✅ | ❌ | ❌ | | `org.read_billing_audit` | View billing-specific audit log | ✅ | ✅ | ✅ | ❌ | Note Organization roles inherit all permissions of the app, channel, and bundle roles below them in the hierarchy. A **Super Admin** can do everything an **App Admin** or **Channel Admin** can do, across all apps and channels. *** ## App roles [Section titled “App roles”](#app-roles) Scoped to a single app. Use these when a team member should only work on one app, not the whole organization. | Role | Internal name | Description | | ----------------- | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | | **App Admin** | `app_admin` | Full control of one app — channels, devices, user roles for the app. Cannot delete or transfer the app (those are org-level operations). | | **App Developer** | `app_developer` | Upload bundles, manage devices, trigger native builds, update channel settings. No deletion, no app settings changes, no channel creation. | | **App Uploader** | `app_uploader` | Read access + upload new bundle versions. | | **App Reader** | `app_reader` | Read-only — stats, bundles, channels, logs, devices. | ### App permission matrix [Section titled “App permission matrix”](#app-permission-matrix) | Permission | Description | App Admin | App Developer | App Uploader | App Reader | | ----------------------- | ------------------------------------- | :-------: | :-----------: | :----------: | :--------: | | `app.read` | View app details, stats, and metadata | ✅ | ✅ | ✅ | ✅ | | `app.update_settings` | Edit app settings | ✅ | ❌ | ❌ | ❌ | | `app.read_bundles` | View the list of uploaded bundles | ✅ | ✅ | ✅ | ✅ | | `app.upload_bundle` | Upload a new bundle version | ✅ | ✅ | ✅ | ❌ | | `app.create_channel` | Create a new channel | ✅ | ❌ | ❌ | ❌ | | `app.read_channels` | View channels | ✅ | ✅ | ✅ | ✅ | | `app.read_logs` | View update delivery logs | ✅ | ✅ | ✅ | ✅ | | `app.manage_devices` | Assign, override, or unlink devices | ✅ | ✅ | ❌ | ❌ | | `app.read_devices` | View the device list | ✅ | ✅ | ✅ | ✅ | | `app.build_native` | Trigger a native cloud build | ✅ | ✅ | ❌ | ❌ | | `app.read_audit` | View app-level activity log | ✅ | ✅ | ✅ | ✅ | | `app.update_user_roles` | Manage app-scoped role assignments | ✅ | ❌ | ❌ | ❌ | | `bundle.delete` | Delete a bundle | ✅ | ❌ | ❌ | ❌ | Note `app.delete` and `app.transfer` are **org-level operations** — only `org_super_admin` can perform them, regardless of app-level roles. *** ## Channel roles [Section titled “Channel roles”](#channel-roles) Scoped to a single channel. Useful for giving targeted access to a specific release channel. Note Channel roles are currently available **via API and CLI only** — there is no UI to assign them in the dashboard. In the dashboard, use [channel permission overrides](/docs/webapp/organization-system/#overriding-channel-permissions) instead to fine-tune channel access per user. | Role | Internal name | Description | | ------------------ | ---------------- | --------------------------------------------------------------------------------------- | | **Channel Admin** | `channel_admin` | Full control of one channel: settings, promote/rollback bundles, manage forced devices. | | **Channel Viewer** | `channel_reader` | Read-only — current bundle, history, forced devices, audit log. | ### Channel permission matrix [Section titled “Channel permission matrix”](#channel-permission-matrix) | Permission | Description | Channel Admin | Channel Viewer | | ------------------------------- | -------------------------------------------------------- | :-----------: | :------------: | | `channel.read` | View the channel and its current bundle | ✅ | ✅ | | `channel.update_settings` | Edit channel settings (platform toggles, update policy…) | ✅ | ❌ | | `channel.delete` | Delete the channel | ✅ | ❌ | | `channel.read_history` | View bundle assignment history | ✅ | ✅ | | `channel.promote_bundle` | Set the active bundle on the channel | ✅ | ❌ | | `channel.rollback_bundle` | Roll back to a previous bundle | ✅ | ❌ | | `channel.manage_forced_devices` | Force specific devices to this channel | ✅ | ❌ | | `channel.read_forced_devices` | View the list of forced devices | ✅ | ✅ | | `channel.read_audit` | View channel activity log | ✅ | ✅ | *** ## Bundle roles [Section titled “Bundle roles”](#bundle-roles) Scoped to a single bundle version. Rarely needed — most teams use app-level roles instead. Note Bundle roles are currently available **via API and CLI only** — there is no UI to assign them in the dashboard. | Role | Internal name | Description | | ----------------- | --------------- | ---------------------------------------------------- | | **Bundle Admin** | `bundle_admin` | Read, update metadata, and delete a specific bundle. | | **Bundle Viewer** | `bundle_reader` | Read-only access to a specific bundle. | *** ## Channel permission overrides (Dashboard) [Section titled “Channel permission overrides (Dashboard)”](#channel-permission-overrides-dashboard) In the dashboard, channel access is determined by the user’s app role by default. For more granular control, you can **override specific channel permissions** per user or group without changing their app role. Overrides are configured from the app’s **Access** tab by clicking the channel permissions button (shield icon) next to a user. See [Organization — Overriding channel permissions](/docs/webapp/organization-system/#overriding-channel-permissions) for a visual walkthrough. ### Overridable permissions [Section titled “Overridable permissions”](#overridable-permissions) | Permission | Description | Default behavior | | -------------------- | ---------------------------------------------- | ----------------------- | | **Read** | View the channel and its current bundle | Inherited from app role | | **History** | View the bundle assignment history | Inherited from app role | | **Associate bundle** | Set or change the active bundle on the channel | Inherited from app role | Each permission can be set to: * **Default** — inherit from the app role (the default) * **Allow** — explicitly grant, regardless of the app role * **Deny** — explicitly block, regardless of the app role This lets you, for example, give an App Reader the ability to associate bundles on the `staging` channel without promoting them to App Developer. *** ## Role hierarchy [Section titled “Role hierarchy”](#role-hierarchy) Roles form a hierarchy. A parent role **inherits all permissions** of its children. This means an `org_admin` can do everything an `app_admin` can, which in turn can do everything a `channel_admin` can, and so on. ```plaintext Super Admin (org_super_admin) └── Admin (org_admin) └── App Admin (app_admin) ├── App Developer (app_developer) │ └── App Uploader (app_uploader) │ └── App Reader (app_reader) ├── Bundle Admin (bundle_admin) │ └── Bundle Viewer (bundle_reader) └── Channel Admin (channel_admin) └── Channel Viewer (channel_reader) ``` **How it works in practice:** * An **Admin** at the org level can do everything an **App Admin** can, on every app in the org. * An **App Admin** on a specific app can do everything a **Channel Admin** can, on every channel in that app. * An **App Developer** can do everything an **App Uploader** can, plus more. The hierarchy only flows **downward** — a `channel_admin` never gains org-level permissions, even if they also hold an app-level role. *** ## Groups [Section titled “Groups”](#groups) Instead of assigning roles to each user individually, you can create **groups** and assign roles to the group. Every member of the group inherits those roles automatically. ### How groups work [Section titled “How groups work”](#how-groups-work) * A group belongs to **one organization** — it cannot span multiple orgs. * Groups can hold role bindings at **any scope**: org, app, channel, or bundle. For example, a group can be assigned the **App Developer** role on App A and the **Channel Admin** role on the `staging` channel of App B. * When a user’s permissions are evaluated, all their group memberships are resolved transparently. If any of their groups grants the required permission, access is allowed. * A user can belong to **multiple groups**, and permissions from all groups are additive. * Group-based permissions only apply to **user principals** — API keys do not inherit group roles. ### When to use groups [Section titled “When to use groups”](#when-to-use-groups) | Scenario | Without groups | With groups | | ---------------------------------------------- | ------------------------------- | -------------------------- | | 5 QA engineers need Developer access to 3 apps | 15 individual role bindings | 1 group + 3 role bindings | | Someone joins the QA team | Add 3 role bindings manually | Add them to the group | | Someone leaves the QA team | Remove 3 role bindings manually | Remove them from the group | ### Managing groups via API [Section titled “Managing groups via API”](#managing-groups-via-api) All group endpoints require authentication and are served under `/private/groups`. #### List groups [Section titled “List groups”](#list-groups) ```bash curl -X GET "https://api.capgo.app/private/groups/<ORG_ID>" \ -H "authorization: <API_KEY>" ``` Requires `org.read_members` permission. #### Create a group [Section titled “Create a group”](#create-a-group) ```bash curl -X POST "https://api.capgo.app/private/groups/<ORG_ID>" \ -H "authorization: <API_KEY>" \ -H "Content-Type: application/json" \ -d '{ "name": "QA Team", "description": "Quality assurance engineers" }' ``` Requires `org.update_user_roles` permission (**Super Admin** or **Admin**). #### Update a group [Section titled “Update a group”](#update-a-group) ```bash curl -X PUT "https://api.capgo.app/private/groups/<GROUP_ID>" \ -H "authorization: <API_KEY>" \ -H "Content-Type: application/json" \ -d '{ "name": "QA Team", "description": "Updated description" }' ``` #### Delete a group [Section titled “Delete a group”](#delete-a-group) ```bash curl -X DELETE "https://api.capgo.app/private/groups/<GROUP_ID>" \ -H "authorization: <API_KEY>" ``` Deleting a group also removes all its role bindings. Members are not deleted from the organization. #### List group members [Section titled “List group members”](#list-group-members) ```bash curl -X GET "https://api.capgo.app/private/groups/<GROUP_ID>/members" \ -H "authorization: <API_KEY>" ``` #### Add a member to a group [Section titled “Add a member to a group”](#add-a-member-to-a-group) ```bash curl -X POST "https://api.capgo.app/private/groups/<GROUP_ID>/members" \ -H "authorization: <API_KEY>" \ -H "Content-Type: application/json" \ -d '{ "user_id": "<USER_UUID>" }' ``` The user must already be a member of the organization. Adding an existing member is a no-op. #### Remove a member from a group [Section titled “Remove a member from a group”](#remove-a-member-from-a-group) ```bash curl -X DELETE "https://api.capgo.app/private/groups/<GROUP_ID>/members/<USER_UUID>" \ -H "authorization: <API_KEY>" ``` Note To assign a role to a group, use the role bindings API with `principal_type: "group"` and `principal_id` set to the group UUID. *** ## Assigning roles via API [Section titled “Assigning roles via API”](#assigning-roles-via-api) ### List members [Section titled “List members”](#list-members) ```bash curl -X GET "https://api.capgo.app/organization/members" \ -H "authorization: <API_KEY>" \ -H "Content-Type: application/json" \ -d '{ "orgId": "<ORG_ID>" }' ``` Response: ```json [ { "uid": "user-uuid", "email": "alice@example.com", "image_url": "https://...", "role": "org_admin", "is_tmp": false } ] ``` ### Invite a member [Section titled “Invite a member”](#invite-a-member) ```bash curl -X POST "https://api.capgo.app/organization/members" \ -H "authorization: <API_KEY>" \ -H "Content-Type: application/json" \ -d '{ "orgId": "<ORG_ID>", "email": "bob@example.com", "invite_type": "org_admin" }' ``` **Accepted values for `invite_type`:** | Value | Role assigned | | ------------------- | --------------- | | `org_super_admin` | Super Admin | | `org_admin` | Admin | | `org_billing_admin` | Billing Manager | | `org_member` | Member | ### Remove a member [Section titled “Remove a member”](#remove-a-member) ```bash curl -X DELETE "https://api.capgo.app/organization/members" \ -H "authorization: <API_KEY>" \ -H "Content-Type: application/json" \ -d '{ "orgId": "<ORG_ID>", "email": "bob@example.com" }' ``` *** ## Assigning roles via CLI [Section titled “Assigning roles via CLI”](#assigning-roles-via-cli) ### List organizations [Section titled “List organizations”](#list-organizations) ```bash npx @capgo/cli organization list --apikey <API_KEY> ``` ### List members [Section titled “List members”](#list-members-1) ```bash npx @capgo/cli organization members <ORG_ID> --apikey <API_KEY> ``` Note The CLI currently supports listing members. To invite members or change roles programmatically, use the API endpoints above. *** ## Custom roles [Section titled “Custom roles”](#custom-roles) The built-in roles cover most team structures. Custom role creation is on our roadmap — if this is something your team needs, [reach out to us](https://support.capgo.app). Your use case will directly help us prioritize this feature. # Organization Security > Configure comprehensive security policies for your organization including 2FA enforcement, password policies, and API key controls to protect your apps and data. Capgo provides comprehensive security controls that allow organization administrators to enforce security policies across all members. These features help you meet compliance requirements, protect sensitive data, and maintain a strong security posture. ## Overview [Section titled “Overview”](#overview) The Organization Security settings allow super admins to configure: * **Two-Factor Authentication (2FA) Enforcement** - Require all members to enable 2FA * **Password Policy** - Set password complexity requirements * **API Key Security** - Enforce secure API keys and expiration policies * **SSO (Enterprise only)** - SAML 2.0 single sign-on for your domain. Available on the Enterprise plan. See [SSO setup guide](/docs/webapp/enterprise-sso/). ![Organization Security Settings](/org_security.webp) The Security page is organized into clearly labeled sections: 1. **Security Tab** - Access all security settings from the Organization settings sidebar 2. **2FA Enforcement** - Toggle and status display for two-factor authentication requirements 3. **Password Policy** - Configure password complexity rules for organization members 4. **API Key Policy** - Settings for secure API keys and expiration requirements 5. **API Key Expiration** - Control whether API keys must have expiration dates Note Only users with **super\_admin** role can configure organization security settings. Other members can view their compliance status but cannot modify the policies. ## Accessing Security Settings [Section titled “Accessing Security Settings”](#accessing-security-settings) 1. Navigate to your organization settings by clicking on **Settings** in the sidebar 2. Click on the **Organization** tab at the top of the settings page 3. Select the **Security** tab from the organization navigation bar (highlighted with a shield icon) ## Two-Factor Authentication (2FA) Enforcement [Section titled “Two-Factor Authentication (2FA) Enforcement”](#two-factor-authentication-2fa-enforcement) 2FA enforcement requires all organization members to have two-factor authentication enabled on their accounts. This adds a critical layer of security by requiring both a password and a verification code. ### What Happens When 2FA is Enforced [Section titled “What Happens When 2FA is Enforced”](#what-happens-when-2fa-is-enforced) * Members without 2FA are **immediately blocked** from accessing organization apps * Both the web dashboard and CLI enforce this requirement * New members must enable 2FA before they can access organization resources * The system tracks which members have 2FA enabled in real-time ### Understanding the 2FA Status Panel [Section titled “Understanding the 2FA Status Panel”](#understanding-the-2fa-status-panel) The Security page displays a comprehensive **Members 2FA Status** panel that shows: * **Total Members** - The total number of members in your organization * **2FA Enabled** (green indicator) - Members who have successfully enabled two-factor authentication * **2FA Not Enabled** (orange warning indicator) - Members who still need to set up 2FA When members don’t have 2FA enabled, they appear in a **Members Without 2FA** warning box. This box shows: * Each member’s email address and their role in the organization * A **Copy Email List** button to quickly copy all affected email addresses for communication ### Enabling 2FA Enforcement [Section titled “Enabling 2FA Enforcement”](#enabling-2fa-enforcement) 1. Navigate to **Organization Settings > Security** 2. Locate the **Require 2FA for All Members** section at the top of the page 3. Review the **Members 2FA Status** panel to see which members will be affected 4. If there are members without 2FA, use the **Copy Email List** button to notify them before enabling 5. Toggle the switch next to **Require 2FA for All Members** to enable enforcement 6. The toggle will show **Disabled** or **Enabled** status on the right side Caution Before enabling 2FA enforcement: * Notify affected members in advance and share the [2FA setup guide](/docs/webapp/mfa/) * Give them time to enable 2FA on their accounts * Members without 2FA will lose access immediately when you enable enforcement * Consider reaching out to members listed in the “Members Without 2FA” warning box ### CLI Support for 2FA Enforcement [Section titled “CLI Support for 2FA Enforcement”](#cli-support-for-2fa-enforcement) You can also manage 2FA enforcement via the CLI: ```shell # Enable 2FA enforcement npx @capgo/cli organization set YOUR_ORG_ID --enforce-2fa # Disable 2FA enforcement npx @capgo/cli organization set YOUR_ORG_ID --no-enforce-2fa # Check member 2FA status npx @capgo/cli organization members YOUR_ORG_ID ``` For detailed information about 2FA enforcement, see the [2FA Enforcement guide](/docs/webapp/2fa-enforcement/). ## Password Policy [Section titled “Password Policy”](#password-policy) Password policies allow you to enforce password complexity requirements for all organization members. When a member’s password doesn’t meet the policy requirements, they must update their password before accessing organization resources. The Password Policy section (marked with indicator **3** in the overview image) provides a simple toggle to enforce password requirements across your organization. ### How Password Policy Works [Section titled “How Password Policy Works”](#how-password-policy-works) When you enable the password policy: * All organization members must meet the password complexity requirements * Users who don’t meet the requirements will be locked out until they update their password * The policy applies to all members regardless of their role ### Enabling Password Policy [Section titled “Enabling Password Policy”](#enabling-password-policy) 1. Go to **Organization Settings > Security** 2. Scroll down to find the **Password Policy** section 3. Read the description: “Require organization members to use passwords that meet specific complexity requirements” 4. Toggle the **Enforce Password Policy** switch to enable it 5. The toggle description states: “When enabled, all organization members must meet the password requirements to access the organization” ### Available Password Requirements [Section titled “Available Password Requirements”](#available-password-requirements) | Setting | Description | Range | | ----------------------------- | ---------------------------------------------------------------------- | ---------------- | | **Minimum Length** | Minimum number of characters required | 6-128 characters | | **Require Uppercase** | Password must contain at least one uppercase letter (A-Z) | On/Off | | **Require Number** | Password must contain at least one digit (0-9) | On/Off | | **Require Special Character** | Password must contain at least one special character (!@#$%^&\*, etc.) | On/Off | ### Member Compliance Tracking [Section titled “Member Compliance Tracking”](#member-compliance-tracking) When a password policy is active, you can monitor compliance: * **Total Members**: Number of members in your organization * **Compliant**: Members whose passwords meet the policy requirements * **Non-Compliant**: Members who need to update their passwords Non-compliant members are listed with their email addresses. You can copy the email list to notify them about the policy and required password changes. Tip When enabling a password policy for the first time, members with non-compliant passwords will be prompted to change their password on their next login. They won’t be immediately locked out, but their access may be restricted until they comply. ### Best Practices for Password Policies [Section titled “Best Practices for Password Policies”](#best-practices-for-password-policies) * **Start with reasonable requirements**: A minimum of 10-12 characters with mixed case and numbers provides good security without being overly restrictive * **Communicate changes**: Notify your team before enabling new password requirements * **Allow transition time**: Give members time to update their passwords * **Consider password managers**: Recommend that team members use password managers to generate and store strong passwords ## API Key Security [Section titled “API Key Security”](#api-key-security) Capgo provides two security controls for API keys: enforcing secure (hashed) API keys and requiring expiration dates. The API Key Policy section (marked with indicator **4** in the overview image) is identified by a key icon. ### Enforce Secure API Keys [Section titled “Enforce Secure API Keys”](#enforce-secure-api-keys) The first option in the API Key Policy section is **Enforce Secure API Keys**. When enabled, this setting requires all API keys in your organization to be created using the secure/hashed format. Hashed API keys are more secure because: * The actual key value is never stored on our servers * Only you (and your systems) have access to the full key * Even if our database were compromised, your keys couldn’t be used The toggle description states: “When enabled, only secure (hashed) API keys can access this organization. Plain-text API keys will be rejected.” Note Existing legacy (non-hashed) API keys will continue to work, but members won’t be able to create new non-hashed keys when this policy is enabled. ### Enabling Secure API Keys [Section titled “Enabling Secure API Keys”](#enabling-secure-api-keys) 1. Go to **Organization Settings > Security** 2. Scroll down to find the **API Key Policy** section (look for the key icon) 3. Locate the **Enforce Secure API Keys** toggle 4. Toggle the switch to enable secure API key enforcement 5. Existing keys are not affected; the policy applies to new key creation ### API Key Expiration Policy [Section titled “API Key Expiration Policy”](#api-key-expiration-policy) The second option (marked with indicator **5** in the overview image) is **Require API Key Expiration**. You can require all API keys to have an expiration date, limiting their validity period. This is a security best practice that: * Limits the window of exposure if a key is compromised * Ensures regular key rotation * Helps meet compliance requirements for credential management The toggle description states: “When enabled, all API keys for this organization must have an expiration date” ### Configuring Expiration Policy [Section titled “Configuring Expiration Policy”](#configuring-expiration-policy) 1. Go to **Organization Settings > Security** 2. Find the **API Key Policy** section 3. Locate the **Require API Key Expiration** toggle (below Enforce Secure API Keys) 4. Toggle the switch to enable the expiration requirement 5. Once enabled, set the **Maximum expiration days** (1-365 days) * This limits how far in the future expiration dates can be set * Example: Setting 90 days means keys can expire at most 90 days from creation Caution When you enable the expiration requirement: * New API keys must have an expiration date * Existing keys without expiration continue to work * Consider auditing existing keys and rotating those without expiration ### Recommended API Key Policies [Section titled “Recommended API Key Policies”](#recommended-api-key-policies) | Use Case | Secure Keys | Expiration | Max Days | | ------------------------- | ----------- | ---------- | -------- | | **Development** | Recommended | Optional | 30-90 | | **CI/CD Pipelines** | Required | Required | 90-180 | | **Production** | Required | Required | 30-90 | | **Enterprise/Compliance** | Required | Required | 30-60 | ## Compliance and Auditing [Section titled “Compliance and Auditing”](#compliance-and-auditing) Organization security features help you meet various compliance requirements: | Standard | Relevant Features | | ------------- | ----------------------------------------------------- | | **SOC 2** | 2FA enforcement, password policies, API key controls | | **ISO 27001** | All security features help demonstrate access control | | **HIPAA** | Strong authentication and access management | | **GDPR** | Data protection through access controls | | **PCI DSS** | Multi-factor authentication, strong passwords | ### Monitoring Compliance Status [Section titled “Monitoring Compliance Status”](#monitoring-compliance-status) The Security dashboard provides real-time visibility into: * How many members have 2FA enabled * Password policy compliance across your organization * API key security adoption Use the “Copy email list” feature to easily export lists of non-compliant members for targeted communication. ## Troubleshooting [Section titled “Troubleshooting”](#troubleshooting) ### ”Access Denied: Security policy not met” [Section titled “”Access Denied: Security policy not met””](#access-denied-security-policy-not-met) **Problem**: A member cannot access the organization. **Solutions**: 1. Check if 2FA is enforced - member needs to [enable 2FA](/docs/webapp/mfa/) 2. Check if password policy is active - member needs to update their password 3. Verify the member’s compliance status in the Security dashboard ### Cannot enable security features [Section titled “Cannot enable security features”](#cannot-enable-security-features) **Problem**: Security toggles are disabled or not responding. **Solutions**: * Ensure you have **super\_admin** role in the organization * Check your network connection * Try refreshing the page * Contact support if the issue persists ### API key creation fails [Section titled “API key creation fails”](#api-key-creation-fails) **Problem**: Cannot create new API keys. **Solutions**: * If secure keys are enforced, ensure you’re using the secure key creation flow * If expiration is required, set an expiration date within the allowed range * Check the maximum expiration days setting ## Next Steps [Section titled “Next Steps”](#next-steps) * [Set up 2FA on your account](/docs/webapp/mfa/) * [Learn about 2FA enforcement details](/docs/webapp/2fa-enforcement/) * [Manage API keys](/docs/webapp/api-keys/) * [Organization management](/docs/webapp/organization-system/) # Organization > Manage your team, control access with role-based permissions, and organize your apps within your Capgo organization. ## What is the organization? [Section titled “What is the organization?”](#what-is-the-organization) The organization lets you share apps with your team while controlling exactly who can do what. Every Capgo account belongs to at least one organization, and you can create as many organizations as you need. Access is managed through **role-based access control (RBAC)**. Each team member is assigned a role — either at the organization level or scoped to a specific app — that determines what they can see and do. Channel access can be further fine-tuned with per-channel permission overrides. *** ## Organization Settings Overview [Section titled “Organization Settings Overview”](#organization-settings-overview) ![Organization Settings Overview](/org-settings-overview.webp) The Organization settings page is accessed by clicking **Settings** in the left sidebar, then selecting the **Organization** tab at the top. From there, you can navigate between the following sections: | Tab | Description | | ---------- | ----------------------------------------------------------- | | General | View and edit organization name, logo, and management email | | Members | Manage team members and their permissions | | Groups | Create and manage groups of users for bulk role assignment | | API Keys | Manage API keys for programmatic access | | Plans | View and manage your subscription plan | | Credits | View and purchase additional credits | | Security | Configure security policies (2FA, password requirements) | | Usage | Monitor your organization’s usage statistics | | Audit Logs | View activity logs for your organization | | Webhooks | Configure webhook integrations | | Billing | Manage billing information and invoices | ### How to switch organizations [Section titled “How to switch organizations”](#how-to-switch-organizations) Click on the **organization selector** dropdown near the top left of the sidebar to view and switch between organizations you have access to. *** ## Managing Members [Section titled “Managing Members”](#managing-members) ### Viewing members [Section titled “Viewing members”](#viewing-members) ![Organization Members List](/org-members-list.webp) The Members section displays all users who have access to your organization with their: * **Member**: Avatar and name * **Role**: Current role (Super Admin, Admin, Billing Manager, or Member) with an **Active** or **Pending** badge * **Actions**: Edit role, manage app-level access, or remove from organization Active members are sorted by role priority. Pending invitations appear with an orange **Pending** badge. ### Inviting a member [Section titled “Inviting a member”](#inviting-a-member) 1. Click the **+ Add** button in the Members section 2. A **Select a role** modal will appear — choose the org-level role for the new member: ![Select a role modal](/org-members-assign-role.webp) The available org-level roles are: * **Member** — Read-only access * **Billing Manager** — Billing-only access * **Admin** — Full administration (no billing, no deletion) * **Super Admin** — Complete control 3. Click **Confirm**, then fill in the invitation form (email, optional first/last name, captcha) and click **Send invitation**. The invited user will receive an email with a magic link. When they accept, they will be added to the organization with the selected role. ### Assigning app-level roles [Section titled “Assigning app-level roles”](#assigning-app-level-roles) Beyond the org-level role, you can give a member access to specific apps with a more targeted role. Click the **Access Control** button (shield icon) next to a member to open the app access modal: ![Access Control modal](/org-members-app-access-control.webp) From this modal you can: 1. Search and select an app 2. Choose an app-level role from the dropdown ![App role dropdown](/org-members-app-role-dropdown.webp) The available app-level roles are: * **App Admin** — Full administration of an app * **App Developer** — Upload bundles, manage devices, but no destructive operations * **App Uploader** — Read app data and upload bundles * **App Reader** — Read-only access to an app 3. Click **Assign** to grant the role. ### Editing a member’s role [Section titled “Editing a member’s role”](#editing-a-members-role) Click the edit button (wrench icon) next to a member to change their org-level role. The same **Select a role** modal will appear with the current role pre-selected. **Constraints:** * You cannot change the role of the organization creator * You cannot remove the last Super Admin — there must always be at least one * Promoting or demoting a Super Admin requires you to be a Super Admin yourself ### Removing a member [Section titled “Removing a member”](#removing-a-member) ![Confirm Delete dialog](/org-members-delete.webp) Click the delete button (trash icon) next to a member. A confirmation dialog will appear warning that this action is not reversible. Click **Delete** to confirm. This revokes all their access to the organization, its apps, and its channels immediately. *** ## Roles overview [Section titled “Roles overview”](#roles-overview) Capgo uses **role-based access control** with roles organized by scope. You can assign a role at the **organization** level (access to everything), or scope it down to a single **app**. Channel access can be further customized with per-channel permission overrides. ### Organization roles [Section titled “Organization roles”](#organization-roles) Assigned when you invite a member. They apply across the entire organization. | Role | Internal name | Description | | ------------------- | ------------------- | ------------------------------------------------------------------------------------------ | | **Super Admin** | `org_super_admin` | Full control — billing, deletion, transfer. Automatically granted to the org creator. | | **Admin** | `org_admin` | Full administration — manage members, apps, channels. No billing, no deletion. | | **Billing Manager** | `org_billing_admin` | Billing only — view/update payment, invoices, billing audit. No access to apps or members. | | **Member** | `org_member` | Read-only access across the org and all its apps. | ### App roles [Section titled “App roles”](#app-roles) Scoped to a single app. Use these when a team member should only work on one app, not the whole organization. | Role | Internal name | Description | | ----------------- | --------------- | ------------------------------------------------------------------------------------------------- | | **App Admin** | `app_admin` | Full control of one app — channels, devices, team. Cannot delete or transfer the app. | | **App Developer** | `app_developer` | Upload bundles, manage devices, trigger builds, update channels. No deletion or settings changes. | | **App Uploader** | `app_uploader` | Read access + upload new bundle versions. | | **App Reader** | `app_reader` | Read-only — stats, bundles, channels, logs, devices. | ### Channel permission overrides [Section titled “Channel permission overrides”](#channel-permission-overrides) By default, channel access is inherited from the app role. You can override specific channel permissions per user or group — for example, allowing an App Reader to also associate bundles on the `staging` channel. See [App-level access management](#app-level-access-management) below for how to configure this. Tip For the full permission breakdown per role, the role hierarchy, and API/CLI usage, see [Access Control Reference](/docs/webapp/organization-roles/). *** ## App-level access management [Section titled “App-level access management”](#app-level-access-management) Each app has a dedicated **Access** tab where you can manage who has access to the app and what they can do — including app roles and per-channel permission overrides. ### Viewing app access [Section titled “Viewing app access”](#viewing-app-access) ![App Access tab](/app-access-tab.webp) Navigate to your app and click the **Access** tab. The access list shows each user or group with their: * **Email** — the user’s email (or group name) * **Role** — their app-level role (App Admin, App Developer, App Uploader, or App Reader) * **Granted at** — when the role was assigned * **Actions** — channel permissions (shield icon), edit role (wrench icon), and remove (trash icon) ### Changing an app role [Section titled “Changing an app role”](#changing-an-app-role) Click the **edit** button (wrench icon) next to a user to change their app-level role: ![Select an app role](/app-access-role-select.webp) Select the new role and click **Confirm**. The available roles are: * **App Developer** — Upload bundles, manage devices, but no destructive operations * **App Uploader** — Read app data and upload bundles * **App Reader** — Read-only access Note **App Admin** is not shown in this modal because it is assigned from the organization-level Members page. See [Assigning app-level roles](#assigning-app-level-roles) above. ### Overriding channel permissions [Section titled “Overriding channel permissions”](#overriding-channel-permissions) Click the **channel permissions** button (shield icon) next to a user to override their default channel permissions: ![Channel permissions modal](/app-access-channel-permissions.webp) The modal shows the user’s current app role and lists all channels with three permissions that can be overridden individually: | Permission | Description | | -------------------- | ---------------------------------------------- | | **Read** | View the channel and its current bundle | | **History** | View the bundle assignment history | | **Associate bundle** | Set or change the active bundle on the channel | Each permission defaults to **Default (allow)** — meaning it inherits from the app role. You can change any permission to explicitly **Allow** or **Deny** for a specific channel, giving you fine-grained control without changing the user’s overall app role. *** ## Groups [Section titled “Groups”](#groups) Groups let you assign roles to a set of users at once instead of managing each member individually. A group belongs to an organization and can hold role bindings at any scope — org or app. **Example:** Create a “QA Team” group, assign it the **App Developer** role on your production app, and every member of that group instantly gets Developer access to that app. When someone joins or leaves the team, just add or remove them from the group — no need to touch individual role bindings. ### How groups work [Section titled “How groups work”](#how-groups-work) * A group is **org-scoped** — it belongs to one organization and cannot span multiple orgs. * You assign roles to a group the same way you assign roles to a user — the group appears as a principal in role bindings. * When a user’s permissions are checked, their group memberships are automatically resolved. If any of their groups hold a role that grants the required permission, access is granted. * A user can belong to multiple groups, and permissions from all groups are combined. ### Viewing groups [Section titled “Viewing groups”](#viewing-groups) ![Groups list](/org-groups-list.webp) Navigate to the **Groups** tab in your organization settings. The groups list shows each group’s **name**, **description**, **role**, **creation date**, and **actions** (edit or delete). ### Creating a group [Section titled “Creating a group”](#creating-a-group) Click the **+ Add** button to open the group creation page: ![Create group page](/org-groups-create.webp) Fill in: 1. **Name** (required) and **Description** (optional) 2. **Organization role** — optionally assign an org-level role (None, Admin, Billing Manager, or Member) 3. **Access Control** tab — assign app-level roles by clicking **+ Add App**, selecting an app, and choosing a role (e.g. App Uploader, App Developer) You need **Super Admin** or **Admin** to create groups. ### Managing group members [Section titled “Managing group members”](#managing-group-members) Click on a group to open its detail view. Switch to the **Members** tab: ![Group detail — Members tab](/org-groups-detail.webp) From here you can view current members and their emails. Click **+ Add** to add members: ![Add members to group](/org-groups-add-members.webp) The modal shows all organization members. Search by name, check the members you want to add, and click **Add members**. Tip For API usage and technical details about groups, see [Access Control Reference — Groups](/docs/webapp/organization-roles/#groups). *** ## Billing [Section titled “Billing”](#billing) Only **Super Admin** (`org_super_admin`) and **Billing Manager** (`org_billing_admin`) can manage billing. Plans are linked to an organization, not to your personal account. Danger Buying a plan will ONLY affect the currently selected organization. *** ## FAQ [Section titled “FAQ”](#faq) ### Can I create more than one organization? [Section titled “Can I create more than one organization?”](#can-i-create-more-than-one-organization) Yes. You can create as many organizations as you need and switch between them using the organization selector in the sidebar. ### How do I configure security policies? [Section titled “How do I configure security policies?”](#how-do-i-configure-security-policies) Super Admins can configure 2FA enforcement, password policies, and API key security from the **Security** tab. See [Organization Security](/docs/webapp/organization-security/) for details. ### Can I give someone access to only one app or channel? [Section titled “Can I give someone access to only one app or channel?”](#can-i-give-someone-access-to-only-one-app-or-channel) Yes — assign them an app-scoped role (like **App Developer** or **App Reader**) via the Members page or the app’s Access tab. You can further fine-tune their access per channel using [channel permission overrides](#overriding-channel-permissions). See [Access Control Reference](/docs/webapp/organization-roles/) for the full list of roles. ### What is the difference between Admin and App Admin? [Section titled “What is the difference between Admin and App Admin?”](#what-is-the-difference-between-admin-and-app-admin) **Admin** (`org_admin`) has authority over the entire organization — all apps, all channels, all members. **App Admin** (`app_admin`) has the same level of control but only over one specific app and its channels. Use App Admin when you want to delegate full control of an app without giving access to the rest of the org. # Payment system > Managing payments in your Capgo account. In this section we show you how to manage your Card, plan, and credits for Capgo ## What is this about? [Section titled “What is this about?”](#what-is-this-about) This page aims to answer some questions about the payment system in capgo. ## Plans [Section titled “Plans”](#plans) #### Q: How can I upgrade my capgo plan? [Section titled “Q: How can I upgrade my capgo plan?”](#q-how-can-i-upgrade-my-capgo-plan) A: You can upgrade your capgo plan by going to [the settings](/docs/webapp/settings/#how-to-get-to-the-settings-page) and clicking on the **Plans** tab (1). ![Plans page](/plans-subscribe.webp) On this page you can: * Toggle between **Monthly Plan** and **Yearly** billing (with a 20% discount for yearly) * Choose from four plans: **Solo**, **Maker**, **Team**, or **Enterprise** * Click **Subscribe** (2) on the plan that best fits your needs Each plan shows: * Monthly price and annual billing total * Monthly active users included and overage pricing * Storage and bandwidth allowances * Build minutes/hours * Features like dedicated support, custom domain, and SOC II compliance If you don’t want to commit to a plan, you can use **credits** instead - click “Learn about credits” to see how pay-as-you-go works. After clicking Subscribe, a Stripe checkout page will open where you can enter your payment information securely. ## Credits [Section titled “Credits”](#credits) Credits provide a flexible alternative to upgrading your plan. They’re useful when: * **Temporary spikes** - You’re temporarily going above your plan limits (e.g., a viral moment, seasonal traffic) and don’t want to upgrade permanently * **Plan mismatch** - The next plan tier doesn’t fit your needs for other reasons (maybe you need more bandwidth but not more MAU) * **Pay-as-you-go preference** - You prefer paying only for what you use beyond your base plan #### Q: How do I access the Credits page? [Section titled “Q: How do I access the Credits page?”](#q-how-do-i-access-the-credits-page) A: Go to [the settings](/docs/webapp/settings/#how-to-get-to-the-settings-page) and click on the **Credits** tab (1). ![Credits page](/buy_credits.webp) The Credits page shows: 1. **Credits tab** - Navigate here from the Organization settings 2. **Credits Balance** - Shows your available credits (e.g., 0.00 / 0.00) and credits used in the current period 3. **Credits Used (USD)** - The estimated dollar value of credits consumed during the current billing period, plus available credits remaining 4. **Need more credits?** - Purchase additional credits instantly to keep your users receiving updates without disruption. Choose from preset amounts ($50, $100, $500, $5000) or enter a custom amount. The estimated total including taxes is shown before checkout 5. **Credit pricing** - Expand this section to see the pricing tiers for different usage types (MAU, storage, bandwidth) 6. **Credit transactions** - View your credit purchase and usage history #### Q: How do I buy credits? [Section titled “Q: How do I buy credits?”](#q-how-do-i-buy-credits) A: On the Credits page, select the amount you want to purchase (or use the dropdown for custom amounts), then click **Buy credits**. You’ll be redirected to Stripe checkout where you can adjust the quantity and complete payment. #### Q: When are credits used? [Section titled “Q: When are credits used?”](#q-when-are-credits-used) A: Credits are automatically consumed when you exceed your plan limits for monthly active users, storage, or bandwidth. They provide a flexible way to handle overages without service interruption #### Q: Are payments secure? [Section titled “Q: Are payments secure?”](#q-are-payments-secure) A: Yes, payments are fully managed by stripe. Capgo never gets access to your credit card details. Stripe takes security very seriously. [Learn more about stripe security policy](https://stripe.com/docs/security/) #### Q: Will capgo automatically upgrade my plan when I exceed the limit? [Section titled “Q: Will capgo automatically upgrade my plan when I exceed the limit?”](#q-will-capgo-automatically-upgrade-my-plan-when-i-exceed-the-limit) A: No, capgo will never change your plan. #### Q: Will cagpo send me an email when my plan is near its limits? [Section titled “Q: Will cagpo send me an email when my plan is near its limits?”](#q-will-cagpo-send-me-an-email-when-my-plan-is-near-its-limits) A: Yes, capgo will send you an email informing you about the usage. #### Q: Will the plan I purchase affect the organizations I am invited to? [Section titled “Q: Will the plan I purchase affect the organizations I am invited to?”](#q-will-the-plan-i-purchase-affect-the-organizations-i-am-invited-to) A: No, the plan will only affect the organization you have currently selected. Please refer to [the organization documentation](/docs/webapp/organization-system/#billing). #### Q: What if I need a more tailored plan? [Section titled “Q: What if I need a more tailored plan?”](#q-what-if-i-need-a-more-tailored-plan) A: [Please contact capgo’s support directly](/docs/getting-help#support-by-chat) #### Q: What is the refund policy for capgo? [Section titled “Q: What is the refund policy for capgo?”](#q-what-is-the-refund-policy-for-capgo) A: A refund policy can be found [here](https://capgo.app/return/) # Settings > How to change the user settings, manage your info, name and email change your picture and more from your Capgo account ## How to get to the settings page [Section titled “How to get to the settings page”](#how-to-get-to-the-settings-page) First click on **your name and picture**. Then click on **Settings**. ![open settings](/settings-go.webp) ## Changing the user settings [Section titled “Changing the user settings”](#changing-the-user-settings) To change any user setting you can just fill out the form in the account and then click on **Update**. ![save change in account](/account-save.webp) Then a confirmation should appear. ![account updated](/account-updated.webp) ## Changing the password [Section titled “Changing the password”](#changing-the-password) To change the password go to the settings page and click on **Password**. Then fill in the form and click on **Update**. ![update password](/update-passwd.webp) When the password does not follow the capgo password security rules then you will get an error message. ![wrong password](/passwd-error.webp)