Diagnosing Capacitor Plugin 'Native Interface Not Available' Failures
Check the native bridge, platform, and sync state before assuming a Capacitor plugin is broken.
23 Jul 2025, 20:12 UTC

Symptom: a Capacitor plugin method returns undefined or rejects with “native interface not available” immediately after the app launches, while ordinary JavaScript continues to run. Useful takeaway: confirm the Capacitor native bridge is ready, the target platform is iOS or Android, and the plugin has been synced into the native project before calling plugin APIs. Do not assume a plugin is broken just because it fails in a browser.
Capacitor is the native bridge that lets a web application call native iOS and Android code through plugins. A web view is the embedded browser component that renders the application’s HTML and JavaScript on a device. npx cap sync is the command that copies installed plugin configuration into the Android and Xcode projects.
Recognizable condition
The failure usually appears at startup. The web portion of the app loads, but the first call to a native plugin—such as reading device information or accessing the camera—returns undefined or throws before reaching native code. The error often names the missing native interface rather than a JavaScript syntax problem.
Cause and diagnostic table
| Observed symptom | Likely cause | First check |
|---|---|---|
| Plugin is undefined immediately after launch | Capacitor native bridge has not initialized | Log window.Capacitor and Capacitor.getPlatform() at startup |
| Plugin exists in package.json but fails in Xcode or Android Studio | npx cap sync was not run after installation |
Run npx cap ls and compare npm vs native entries |
| Works on emulator, fails on physical device | Missing native permission or device trust issue | Inspect Xcode console or Android Logcat |
| Fails in browser but works on device | Native plugins are unavailable in web or PWA context by design | Confirm Capacitor.getPlatform() returns web |
Ordered checks
- Confirm
window.Capacitorexists. Add a startup log before any plugin call:
Run in the app on a device or emulator. No special permissions are required. Expected result: an object is logged. If the log showsconsole.log('Capacitor global:', window.Capacitor);undefined, the native bridge has not been exposed to the web view yet. - Confirm the platform is not web.
Expected result on iOS or Android:import { Capacitor } from '@capacitor/core'; console.log('Platform:', Capacitor.getPlatform());iosorandroid. Expected result in a browser or desktop PWA:web. If the result isweb, native plugins are unavailable by design. - Confirm the plugin is synced to native projects. Run in the project root:
This is a read-only command and requires no elevated permissions. Expected output lists installed plugins and the native platforms configured. If a plugin appears under npm dependencies but not under the native project, run:npx cap ls
Replacenpx cap sync <platform><platform>withandroidorios. This command modifies theandroid/orios/directories and requires write access to them. Risk: it can overwrite manual native edits, so commit or back up native changes first. - Check native permissions. If the bridge and sync state are correct but the plugin still fails, inspect the native project files. Camera, location, and notifications require entries in
AndroidManifest.xmlon Android orInfo.pliston iOS. Capacitor configuration alone does not grant these permissions. - Compare browser and native behavior. Run
npm run devin a browser and then open the native project withnpx cap open iosornpx cap open android. Opening iOS requires macOS and Xcode. If the plugin works in the native project but not in the browser, the issue is the missing native bridge, not the plugin code.
Fixes tied to findings
Guard plugin calls with a platform check
import { Capacitor, Plugins } from '@capacitor/core';
const { Device } = Plugins;
async function readDeviceInfo() {
if (!window.Capacitor) {
console.warn('Capacitor native bridge is not present in this context');
return;
}
const platform = Capacitor.getPlatform();
if (platform === 'web') {
console.log('Running in a browser or PWA; native plugin skipped');
return;
}
try {
const info = await Device.getInfo();
console.log('Native platform info:', info);
} catch (error) {
console.error('Device plugin call failed:', error);
}
}
Install the corresponding plugin package, such as @capacitor/device, before importing it. The guard prevents calls in browser or PWA contexts where window.Capacitor is absent or the platform is web.
Run npx cap sync after plugin changes
Whenever a plugin is added, removed, or updated, run npx cap sync from the project root. Use npx cap sync android or npx cap sync ios to target one platform. Expected check: run npx cap ls afterward and confirm the plugin appears in both the npm dependency list and the native project files.
Declare permissions in native project files
For example, a camera plugin may require:
<uses-permission android:name="android.permission.CAMERA" />
in AndroidManifest.xml, and:
<key>NSCameraUsageDescription</key>
<string>This app needs camera access to scan barcodes.</string>
in Info.plist. Exact keys depend on the plugin; consult the plugin documentation rather than copying these examples blindly.
Escalation criteria
- Plugin works on an emulator but fails on a physical device: inspect device logs and native permission grants. Physical devices often enforce privacy prompts that emulators skip.
- A clean rebuild and
npx cap syncdo not resolve the issue: collect Xcode console output or Android Logcat and contact the plugin maintainer. Include the Capacitor version and plugin version.
Limitations and verification
- Capacitor behavior differs across major versions such as 3, 4, and 6. Check the installed version in
package.jsonbefore applying version-specific syntax. - Do not use Cordova’s
devicereadyevent; Capacitor uses its own native bridge readiness model. - iOS WKWebView can silently drop plugin calls made outside the main web-view lifecycle.
- Native permissions must be declared in
Info.plistorAndroidManifest.xml; Capacitor configuration alone is insufficient.
Practical verification: add a startup log that prints Capacitor.getPlatform(), run npx cap ls after syncing, and reproduce the failure in both a browser and a native build. If the platform log prints ios or android on a device and npx cap ls lists the plugin under both npm and native entries, the bridge and sync state are confirmed.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.