[{"data":1,"prerenderedAt":882},["ShallowReactive",2],{"docs-page:en:\u002Fdocs\u002Ftooling\u002Fsdk":3,"docs-navigation:en":784},{"id":4,"title":5,"body":6,"description":776,"extension":777,"meta":778,"navigation":779,"path":780,"seo":781,"stem":782,"__hash__":783},"docs_en\u002Fen\u002Fdocs\u002Ftooling\u002Fsdk.md","SDKs",{"type":7,"value":8,"toc":754},"minimark",[9,13,16,31,34,37,40,45,65,69,72,90,118,121,135,145,149,152,155,228,231,285,297,302,307,310,327,330,342,347,350,364,368,383,403,418,423,428,440,445,462,466,472,492,497,514,518,521,529,538,542,553,560,567,570,585,589,592,606,609,613,626,631,635,693,697,700,714,717,731,734,738,743,751],[10,11,12],"p",{},"Otalan does not ship one universal mobile SDK because the runtime responsibilities are different across ecosystems.",[10,14,15],{},"The two main client-side packages serve different purposes:",[17,18,19,26],"ul",{},[20,21,22],"li",{},[23,24,25],"code",{},"@otalan\u002Fcapacitor",[20,27,28],{},[23,29,30],{},"@otalan\u002Fexpo",[10,32,33],{},"Choosing the wrong one usually leads to a confused integration, so it is worth understanding the split clearly.",[10,35,36],{},"Otalan does not block older runtime versions by version number. Official support currently covers Capacitor 7 and 8, and Expo 54, 55, and 56. Other runtimes and older Expo or Capacitor versions might work or might not, but they are not supported for the moment.",[10,38,39],{},"References to Expo, Capawesome, Capacitor, and their packages are integration references only. Otalan is independent and is not affiliated with, endorsed by, sponsored by, or authorized by Expo or Capawesome.",[41,42,44],"h2",{"id":43},"published-packages","Published packages",[17,46,47,57],{},[20,48,49],{},[50,51,55],"a",{"href":52,"rel":53},"https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002F@otalan\u002Fcapacitor",[54],"nofollow",[23,56,25],{},[20,58,59],{},[50,60,63],{"href":61,"rel":62},"https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002F@otalan\u002Fexpo",[54],[23,64,30],{},[41,66,68],{"id":67},"runtime-setup-requirements","Runtime setup requirements",[10,70,71],{},"You do not need Bun to install either SDK in an app. Bun is a CLI requirement, not a mobile runtime requirement.",[10,73,74,75,77,78,81,82,85,86,89],{},"For Capacitor, install ",[23,76,25],{}," with ",[23,79,80],{},"@capawesome\u002Fcapacitor-live-update",", ",[23,83,84],{},"@capacitor\u002Fapp",", and ",[23,87,88],{},"@capacitor\u002Fcore",". Use the OTA App Key in the app and keep OTA Publish Keys out of frontend code.",[10,91,92,93,77,95,98,99,102,103,105,106,109,110,113,114,117],{},"For Expo, install ",[23,94,30],{},[23,96,97],{},"expo-updates"," and ",[23,100,101],{},"expo-application",". Point ",[23,104,97],{}," at the Otalan manifest endpoint, include the OTA App Key in update request headers, and call the initialized helper's ",[23,107,108],{},"check()"," method when you only need ",[23,111,112],{},"updateAvailable",", or ",[23,115,116],{},"sync()"," when the app should check and apply OTA work.",[10,119,120],{},"Both runtimes work best when the OTA payload stays small. Keep images, videos, large fonts, PDFs, and marketing media hosted externally instead of embedding them in the web bundle.",[10,122,123,124,127,128,130,131,113,133,117],{},"Both SDKs handle the stable rollout identity through ",[23,125,126],{},"initializeUpdater()",". Keep the initialized updater instance around and call ",[23,129,108],{}," when you only need ",[23,132,112],{},[23,134,116],{},[10,136,137,138,140,141,144],{},"For Expo, ",[23,139,30],{}," creates and persists the stable rollout device ID, then writes it to Expo update extra params as ",[23,142,143],{},"otalan-device-id"," before checking for updates. App code does not need to set a separate Otalan device header.",[41,146,148],{"id":147},"app-variables","App variables",[10,150,151],{},"The app uses an OTA App Key. Never ship an OTA Publish Key in the mobile app.",[10,153,154],{},"Typical Capacitor app variables:",[156,157,158,171],"table",{},[159,160,161],"thead",{},[162,163,164,168],"tr",{},[165,166,167],"th",{},"Variable",[165,169,170],{},"Purpose",[172,173,174,185,195,208,218],"tbody",{},[162,175,176,182],{},[177,178,179],"td",{},[23,180,181],{},"VITE_OTALAN_API_URL",[177,183,184],{},"Public Otalan API URL used by the runtime client",[162,186,187,192],{},[177,188,189],{},[23,190,191],{},"VITE_OTALAN_APP_KEY",[177,193,194],{},"OTA App Key created in the dashboard",[162,196,197,202],{},[177,198,199],{},[23,200,201],{},"VITE_OTALAN_APP_ID",[177,203,204,205],{},"Registered app ID, such as ",[23,206,207],{},"com.example.app",[162,209,210,215],{},[177,211,212],{},[23,213,214],{},"VITE_OTALAN_CHANNEL",[177,216,217],{},"Release channel the installed build checks",[162,219,220,225],{},[177,221,222],{},[23,223,224],{},"VITE_OTALAN_RUNTIME_VERSION",[177,226,227],{},"Native compatibility line for this installed build",[10,229,230],{},"Typical Expo app variables:",[156,232,233,241],{},[159,234,235],{},[162,236,237,239],{},[165,238,167],{},[165,240,170],{},[172,242,243,253,263,273],{},[162,244,245,250],{},[177,246,247],{},[23,248,249],{},"EXPO_PUBLIC_OTALAN_API_URL",[177,251,252],{},"Public Otalan API URL used to build the update URL",[162,254,255,260],{},[177,256,257],{},[23,258,259],{},"EXPO_PUBLIC_OTALAN_APP_KEY",[177,261,262],{},"OTA App Key sent in update request headers",[162,264,265,270],{},[177,266,267],{},[23,268,269],{},"EXPO_PUBLIC_OTALAN_APP_ID",[177,271,272],{},"Registered app ID used by the manifest endpoint",[162,274,275,280],{},[177,276,277],{},[23,278,279],{},"EXPO_PUBLIC_OTALAN_CHANNEL",[177,281,282,283],{},"Release channel for ",[23,284,97],{},[10,286,137,287,290,291,293,294,296],{},[23,288,289],{},"runtimeVersion"," belongs in the Expo config used by ",[23,292,97],{},". Keep it aligned with the ",[23,295,289],{}," used when publishing the bundle.",[41,298,300],{"id":299},"otalancapacitor",[23,301,25],{},[10,303,304,306],{},[23,305,25],{}," is the full Otalan runtime client for Capacitor applications.",[10,308,309],{},"Use it when you want Otalan to participate directly in the update lifecycle:",[17,311,312,315,318,321,324],{},[20,313,314],{},"checking for updates",[20,316,317],{},"downloading the selected bundle",[20,319,320],{},"staging the next bundle",[20,322,323],{},"reloading into the installed bundle",[20,325,326],{},"confirming a successful install back to Otalan",[10,328,329],{},"This package is appropriate when your app wants the control plane to own the OTA decision flow from update check to confirmation.",[10,331,332,333,81,336,85,338,341],{},"Install confirmation uses the ",[23,334,335],{},"channel",[23,337,289],{},[23,339,340],{},"bundleId"," returned by the update check, so repeated bundle IDs in separate targets do not collide.",[343,344,346],"h3",{"id":345},"typical-fit","Typical fit",[10,348,349],{},"Choose this package when:",[17,351,352,355,358,361],{},[20,353,354],{},"the mobile app is built with Capacitor",[20,356,357],{},"the app can provide a stable device identifier",[20,359,360],{},"you want deterministic rollout behavior",[20,362,363],{},"you want install confirmation and analytics tied directly to the Otalan flow",[343,365,367],{"id":366},"startup-and-api-shape","Startup and API shape",[10,369,370,371,374,375,378,379,382],{},"The high-level entry point is ",[23,372,373],{},"initializeUpdater(config)",". It can resolve ",[23,376,377],{},"appId",", create a stable device ID, start ",[23,380,381],{},"LiveUpdate.ready()"," and install confirmation in the background, optionally sync on resume, and expose:",[17,384,385,390,395,399],{},[20,386,387],{},[23,388,389],{},"getDeviceId()",[20,391,392],{},[23,393,394],{},"getUpdater()",[20,396,397],{},[23,398,108],{},[20,400,401],{},[23,402,116],{},[10,404,405,406,409,410,81,413,85,415,417],{},"Use ",[23,407,408],{},"createUpdater(config)"," only when you want to orchestrate the lower-level flow yourself with ",[23,411,412],{},"ready()",[23,414,108],{},[23,416,116],{},".",[41,419,421],{"id":420},"otalanexpo",[23,422,30],{},[10,424,425,427],{},[23,426,30],{}," is intentionally smaller.",[10,429,430,431,433,434,437,438,417],{},"For Expo apps using ",[23,432,97],{},", the runtime updater already exists. Otalan's role is to serve the authenticated manifest, return immutable asset URLs, and receive confirmation or startup metadata that helps the platform understand what happened. ",[23,435,436],{},"InitializedExpoUpdater.sync()"," sets the Otalan request context, then calls Expo's check, fetch, and reload APIs through ",[23,439,97],{},[10,441,405,442,444],{},[23,443,30],{}," when you want:",[17,446,447,450,453,456],{},[20,448,449],{},"startup metadata helpers",[20,451,452],{},"current update metadata",[20,454,455],{},"install confirmation after a successful launch",[20,457,458,459,461],{},"an Otalan-aware layer on top of ",[23,460,97],{},", not a replacement for it",[343,463,465],{"id":464},"expo-staged-rollouts","Expo staged rollouts",[10,467,468,469,471],{},"Partial rollouts for Expo should go through ",[23,470,436],{}," so Otalan can attach the runtime metadata it needs before Expo performs update work.",[10,473,474,475,478,479,482,483,485,486,488,489,491],{},"Keep ",[23,476,477],{},"checkAutomatically"," as ",[23,480,481],{},"NEVER"," and call ",[23,484,108],{}," for ",[23,487,112],{}," or ",[23,490,116],{}," for check-and-apply work from a controlled app startup or settings-screen path. That keeps update checks under Otalan's helper instead of letting Expo check before the helper is initialized.",[10,493,494,496],{},[23,495,30],{}," confirms launched OTA updates for install analytics. Confirmation records include the release channel and runtime version so reused bundle IDs stay scoped to the right target. Transfer usage is counted when the API returns a Capacitor bundle URL or serves an Expo manifest.",[10,498,499,500,502,503,505,506,509,510,513],{},"Expo download progress is still owned by ",[23,501,97],{},". ",[23,504,30],{}," does not expose an Otalan ",[23,507,508],{},"onDownloadProgress"," callback; use Expo state such as ",[23,511,512],{},"useUpdates().downloadProgress"," when the app needs progress UI.",[41,515,517],{"id":516},"the-practical-difference","The practical difference",[10,519,520],{},"The simplest way to remember the split is this:",[17,522,523,526],{},[20,524,525],{},"Capacitor: Otalan is deeply involved in runtime update orchestration",[20,527,528],{},"Expo: Expo still owns runtime update orchestration, and Otalan integrates around it",[10,530,531,532,534,535,537],{},"Expo asset downloads use the immutable asset URLs returned by the Otalan manifest. ",[23,533,30],{}," triggers the check\u002Ffetch\u002Freload path through ",[23,536,97],{},", but Expo still owns the download state and runtime installation.",[41,539,541],{"id":540},"local-device-networking","Local device networking",[10,543,544,545,548,549,552],{},"Native app runtimes must be able to reach the configured API URL. A local API URL such as ",[23,546,547],{},"http:\u002F\u002Flocalhost:8787"," usually works only from the same host process. Physical devices usually need the machine's LAN IP, Android emulators often need ",[23,550,551],{},"10.0.2.2",", and plain HTTP may require platform cleartext or ATS development settings.",[10,554,555,556,559],{},"For Android local HTTP testing, enable cleartext only in the development build, for example with ",[23,557,558],{},"android:usesCleartextTraffic=\"true\""," in the Android manifest or the framework's equivalent Android config. Do not ship that setting in production.",[10,561,562,563,566],{},"For Capacitor bundle downloads over plain HTTP in local development, pass ",[23,564,565],{},"allowInsecureBundleUrls: true",". Do not enable that for production.",[10,568,569],{},"That difference should also influence how you publish:",[17,571,572,582],{},[20,573,574,575,578,579],{},"manual dashboard publishing is workable for either model, but upload ",[23,576,577],{},".otalan\u002Fbundle\u002Fbundle-\u003Cbundle-id>.zip"," from ",[23,580,581],{},"otalan bundle",[20,583,584],{},"CLI automation is especially attractive for Expo because export metadata and packaging need to stay aligned",[41,586,588],{"id":587},"shared-operational-expectations","Shared operational expectations",[10,590,591],{},"Regardless of runtime, a correct integration still needs:",[17,593,594,597,600,603],{},[20,595,596],{},"the right project-scoped credentials",[20,598,599],{},"exact tuple targeting",[20,601,602],{},"a clear distinction between native releases and OTA web releases",[20,604,605],{},"discipline around rollout and rollback",[10,607,608],{},"The runtime package solves only one part of the overall product behavior.",[41,610,612],{"id":611},"rollback-behavior","Rollback behavior",[10,614,615,616,81,618,81,621,85,623,625],{},"Rollback happens on the Otalan server side. When an older bundle is reactivated for the same ",[23,617,377],{},[23,619,620],{},"platform",[23,622,335],{},[23,624,289],{},", clients receive that active bundle on their next eligible check.",[10,627,628,629,417],{},"The SDKs do not override native compatibility rules. If the broken release requires native code, plugins, permissions, entitlements, or a different Expo runtime version, ship a new app-store binary and publish future OTA updates on a new ",[23,630,289],{},[41,632,634],{"id":633},"common-failure-modes","Common failure modes",[17,636,637,640,646,656,659,662,672,681,687],{},[20,638,639],{},"an OTA Publish Key was shipped in the app instead of an OTA App Key",[20,641,642,643,645],{},"the app sends an ",[23,644,377],{}," that is not registered in the selected Otalan project",[20,647,648,649,81,651,113,653,655],{},"published ",[23,650,620],{},[23,652,335],{},[23,654,289],{}," does not match the installed build",[20,657,658],{},"the bundle expects native code or plugins that are not in the installed binary",[20,660,661],{},"Capacitor did not persist a stable device ID before rollout cohort assignment",[20,663,664,665,667,668,671],{},"Expo native config omits ",[23,666,101],{}," or the ",[23,669,670],{},"x-api-key"," request header required by the Otalan manifest endpoint",[20,673,674,675,488,678],{},"Expo update checks bypass ",[23,676,677],{},"updater.check()",[23,679,680],{},"updater.sync()",[20,682,683,684,686],{},"Expo ",[23,685,477],{}," runs before the Otalan helper is initialized",[20,688,689,690],{},"Expo publish used a raw Expo config instead of the generated Otalan ",[23,691,692],{},".otalan\u002Fbundle\u002Fmanifest.json",[41,694,696],{"id":695},"how-much-setup-is-covered-here","How much setup is covered here",[10,698,699],{},"These docs now include first-pass setup examples in the runtime quick starts:",[17,701,702,708],{},[20,703,704],{},[50,705,707],{"href":706},"\u002Fdocs\u002Fquick-start\u002Fexpo","Expo quick start",[20,709,710],{},[50,711,713],{"href":712},"\u002Fdocs\u002Fquick-start\u002Fcapacitor","Capacitor quick start",[10,715,716],{},"The package-level references still own exhaustive details for:",[17,718,719,722,725,728],{},[20,720,721],{},"installation",[20,723,724],{},"framework-specific code samples",[20,726,727],{},"runtime API signatures",[20,729,730],{},"troubleshooting edge cases",[10,732,733],{},"Those details should live with the package that actually ships the runtime code, but you should not need them just to understand the first integration path.",[41,735,737],{"id":736},"choosing-the-right-package","Choosing the right package",[10,739,405,740,742],{},[23,741,25],{}," if the app is a Capacitor app and you want a full Otalan-driven OTA client.",[10,744,405,745,747,748,750],{},[23,746,30],{}," if the app uses Expo with ",[23,749,97],{}," and only needs Otalan-specific metadata and confirmation support around that runtime.",[10,752,753],{},"If your team keeps that distinction clear from the beginning, the rest of the platform model stays much easier to reason about.",{"title":755,"searchDepth":756,"depth":756,"links":757},"",3,[758,760,761,762,766,769,770,771,772,773,774,775],{"id":43,"depth":759,"text":44},2,{"id":67,"depth":759,"text":68},{"id":147,"depth":759,"text":148},{"id":299,"depth":759,"text":25,"children":763},[764,765],{"id":345,"depth":756,"text":346},{"id":366,"depth":756,"text":367},{"id":420,"depth":759,"text":30,"children":767},[768],{"id":464,"depth":756,"text":465},{"id":516,"depth":759,"text":517},{"id":540,"depth":759,"text":541},{"id":587,"depth":759,"text":588},{"id":611,"depth":759,"text":612},{"id":633,"depth":759,"text":634},{"id":695,"depth":759,"text":696},{"id":736,"depth":759,"text":737},"Understand the difference between the Capacitor and Expo integrations, and choose the runtime package that matches the way your mobile app actually updates.","md",{},true,"\u002Fen\u002Fdocs\u002Ftooling\u002Fsdk",{"title":5,"description":776},"en\u002Fdocs\u002Ftooling\u002Fsdk","3U2TCqnV0psWD40yZqv3fa_DuPmpid-KsKEAR-PfUHA",[785],{"title":786,"path":787,"stem":788,"children":789,"page":807},"En","\u002Fen","en",[790],{"title":791,"path":792,"stem":793,"children":794,"description":796},"Introduction","\u002Fen\u002Fdocs","en\u002Fdocs\u002Findex",[795,797,808,818,828,838,856,872],{"title":791,"path":792,"stem":793,"description":796},"Understand what Otalan is, when to use it, and how the first safe OTA release flow works for Capacitor and Expo apps.",{"title":798,"path":799,"stem":800,"children":801,"page":807},"About","\u002Fen\u002Fdocs\u002Fabout","en\u002Fdocs\u002Fabout",[802],{"title":803,"path":804,"stem":805,"description":806},"Security and trust","\u002Fen\u002Fdocs\u002Fabout\u002Fsecurity-trust","en\u002Fdocs\u002Fabout\u002Fsecurity-trust","How Otalan keeps OTA releases controlled: scoped keys, bundle validation, exact matching, rollout controls, rollback, deletion behavior, and support contact.",false,{"title":809,"path":810,"stem":811,"children":812,"page":807},"Build","\u002Fen\u002Fdocs\u002Fbuild","en\u002Fdocs\u002Fbuild",[813],{"title":814,"path":815,"stem":816,"description":817},"Generate a bundle","\u002Fen\u002Fdocs\u002Fbuild\u002Fgenerate-bundle","en\u002Fdocs\u002Fbuild\u002Fgenerate-bundle","Prepare a release artifact that will pass Otalan's validation pipeline, including the extra considerations required for Expo-based publish flows.",{"title":819,"path":820,"stem":821,"children":822,"page":807},"Deploy","\u002Fen\u002Fdocs\u002Fdeploy","en\u002Fdocs\u002Fdeploy",[823],{"title":824,"path":825,"stem":826,"description":827},"Publish a release","\u002Fen\u002Fdocs\u002Fdeploy\u002Fpublish-release","en\u002Fdocs\u002Fdeploy\u002Fpublish-release","Submit a release through the dashboard, understand each field in the publish form, and operate the validation lifecycle with confidence.",{"title":829,"path":830,"stem":831,"children":832,"page":807},"Integration","\u002Fen\u002Fdocs\u002Fintegration","en\u002Fdocs\u002Fintegration",[833],{"title":834,"path":835,"stem":836,"description":837},"Migrate from App Center CodePush","\u002Fen\u002Fdocs\u002Fintegration\u002Fapp-center-codepush","en\u002Fdocs\u002Fintegration\u002Fapp-center-codepush","Plan a migration from Microsoft App Center CodePush to Otalan, with mapping notes, rollout guidance, and common failure modes.",{"title":839,"path":840,"stem":841,"children":842,"page":807},"Quick Start","\u002Fen\u002Fdocs\u002Fquick-start","en\u002Fdocs\u002Fquick-start",[843,847,851],{"title":713,"path":844,"stem":845,"description":846},"\u002Fen\u002Fdocs\u002Fquick-start\u002Fcapacitor","en\u002Fdocs\u002Fquick-start\u002Fcapacitor","Wire the Otalan Capacitor runtime into an installed app so it can check for OTA updates, install compatible bundles, and confirm successful launches.",{"title":707,"path":848,"stem":849,"description":850},"\u002Fen\u002Fdocs\u002Fquick-start\u002Fexpo","en\u002Fdocs\u002Fquick-start\u002Fexpo","Configure expo-updates with Otalan, add the Otalan Expo helper, and make the installed app ready to receive compatible OTA bundles.",{"title":852,"path":853,"stem":854,"description":855},"Publish in 5 minutes","\u002Fen\u002Fdocs\u002Fquick-start\u002Fquick-start","en\u002Fdocs\u002Fquick-start\u002Fquick-start","Create the first Otalan release path, publish a baseline bundle, verify one update, and prove rollback before widening rollout.",{"title":857,"path":858,"stem":859,"children":860,"page":807},"Tooling","\u002Fen\u002Fdocs\u002Ftooling","en\u002Fdocs\u002Ftooling",[861,866,871],{"title":862,"path":863,"stem":864,"description":865},"AI skill","\u002Fen\u002Fdocs\u002Ftooling\u002Fai-skill","en\u002Fdocs\u002Ftooling\u002Fai-skill","Copy a compact assistant skill for Otalan SDK setup, CLI publishing, and safe credential boundaries.",{"title":867,"path":868,"stem":869,"description":870},"CLI","\u002Fen\u002Fdocs\u002Ftooling\u002Fcli","en\u002Fdocs\u002Ftooling\u002Fcli","Learn when to use the Otalan CLI, what workflows it covers, and how it complements the dashboard instead of replacing the platform model.",{"title":5,"path":780,"stem":782,"description":776},{"title":873,"path":874,"stem":875,"children":876,"page":807},"Versions","\u002Fen\u002Fdocs\u002Fversions","en\u002Fdocs\u002Fversions",[877],{"title":878,"path":879,"stem":880,"description":881},"v1","\u002Fen\u002Fdocs\u002Fversions\u002Fv1","en\u002Fdocs\u002Fversions\u002Fv1","Supported runtimes, public limits, and post-v1 candidates for Otalan v1.",1780287527003]