@elizaos/capacitor-agent
Capacitor plugin for managing an embedded Eliza agent runtime from a WebView-based app. Provides a uniform Agent.* JavaScript API across iOS, Android, and web/desktop, with platform-specific native bridges and an HTTP-based web fallback.
What it does
- Start / stop the agent runtime and poll its state.
- Send chat messages (DM channel) and receive agent replies.
- Forward arbitrary HTTP requests to the local agent API server via a path-only bridge.
- Read the per-boot bearer token on Android local deployments.
The plugin handles three deployment shapes automatically:
| Platform | Mechanism |
|---|---|
| iOS remote/cloud | HTTP to a configured API endpoint (reads ELIZA_IOS_API_BASE or equivalent) |
| iOS local / sideload | WebView ITTP bridge (window.__ELIZA_BRIDGE__?.iosLocalAgentRequest) |
| Android local | Reflection call into ElizaAgentService in the host app |
| Web / Electrobun | HTTP fetch to the boot-config apiBase or relative URLs |
Capacitor methods
import { Agent } from "@elizaos/capacitor-agent";
// Start the agent
const status = await Agent.start({ mode: "cloud" });
// Get status
const status = await Agent.getStatus();
// status.state: "not_started" | "starting" | "running" | "stopped" | "error"
// Chat
const reply = await Agent.chat({ text: "Hello" });
// reply.text, reply.agentName
// Forward a request
const result = await Agent.request({
path: "/api/status",
method: "GET",
timeoutMs: 5000,
});
// Stop the agent
await Agent.stop();
// Read local agent token (Android only)
const { available, token } = await Agent.getLocalAgentToken();
Installation
This is a Capacitor plugin distributed as part of the elizaOS monorepo. Add it as a dependency in your Capacitor app, then run npx cap sync to install the native modules.
npm install @elizaos/capacitor-agent
npx cap sync
iOS (CocoaPods)
The pod is named ElizaosCapacitorAgent. It is registered automatically via capacitor.config after pod install. Minimum deployment target: iOS 13.0 (note: local ITTP mode requires iOS 14+).
Android
The plugin is registered automatically. The host app must implement ElizaAgentService and register it in AndroidManifest.xml. The plugin locates it via reflection (no direct Gradle dependency).
Configuration
iOS endpoint (remote/cloud mode)
Set one of the following in your capacitor.config.json (under the Agent plugin key), Info.plist, or environment:
ELIZA_AGENT_API_BASE/ELIZA_IOS_API_BASE/ELIZA_MOBILE_API_BASE— HTTP/HTTPS base URL of the agent API serverELIZA_AGENT_API_TOKEN/ELIZA_IOS_API_TOKEN/ELIZA_MOBILE_API_TOKEN— optional bearer tokenELIZA_IOS_RUNTIME_MODE/VITE_ELIZA_IOS_RUNTIME_MODE— set tolocal/ios-local/sideload-localto activate local ITTP mode instead of HTTP
Example capacitor.config.json fragment:
{
"plugins": {
"Agent": {
"apiBase": "https://your-eliza-host.example.com",
"apiToken": "your-bearer-token"
}
}
}
Web / Electrobun
- boot-config
apiBase(window.__ELIZAOS_APP_BOOT_CONFIG__) — API server base URL; falls back to relative URLs onhttp:/https:origins. window.__ELIZA_API_TOKEN__— bearer token; falls back tosessionStorage.eliza_api_token.
Exported types
interface AgentStatus {
state: "not_started" | "starting" | "running" | "stopped" | "error";
agentName: string | null;
port: number | null;
startedAt: number | null; // epoch ms
error: string | null;
}
interface ChatResult {
text: string;
agentName: string;
}
interface AgentStartOptions {
apiBase?: string;
mode?: "remote-mac" | "cloud" | "cloud-hybrid" | "local" | string;
}
interface AgentRequestOptions {
path: string; // must start with /, not an absolute URL
method?: string;
headers?: Record<string, string>;
body?: string | null;
timeoutMs?: number;
}
interface AgentRequestResult {
status: number;
statusText: string;
headers: Record<string, string>;
body: string;
}
Building
bun run --cwd plugins/plugin-native-agent build # tsc + rollup → dist/
bun run --cwd plugins/plugin-native-agent watch # tsc --watch
Limitations
Agent.requestonly accepts path-only URLs (must start with/). Absolute URLs are rejected by all implementations.- Request and response bodies are capped at 10 MB.
- iOS local mode (
Agent.chat/Agent.requestvia ITTP) requireswindow.__ELIZA_BRIDGE__?.iosLocalAgentRequestto be installed by the host WebView. If it is absent, a 503 is returned. - The Android bridge uses reflection; renaming or unregistering
ElizaAgentServicebreaks all Android calls silently at runtime. - The
chatmethod maintains one conversation per session (lazily created viaPOST /api/conversations). The conversation ID is not persisted across app restarts.