Browser & Webview Runtimes

Run PraisonAI Agents inside browsers, Electron, Tauri, and React Native

PraisonAI Agents run anywhere JavaScript runs — browsers, Electron, Tauri webviews, and React Native — with zero extra setup.

Diagram

PraisonAI Agent — everywhere JS runs

🖥️ Node

🤖 Agent

🌐 Browser

💻 Electron

🪟 Tauri Webview

📱 React Native

🧠 OpenAI SDK

Quick Start

The runtime is detected automatically — pass credentials directly on the Agent.

  1. Browser / Electron renderer (auto-detected)

    The browser guard is enabled for you — no config needed.

    typescript
    import { Agent } from 'praisonai';
    
    const agent = new Agent({
      instructions: "You are a helpful assistant",
      apiKey: import.meta.env.VITE_OPENAI_KEY,
    });
    
    await agent.chat("Hello from the browser!");
  2. Tauri / native fetch bridge

    Pass a custom fetch to route requests through native code — the key stays out of the JS heap.

    typescript
    import { Agent } from 'praisonai';
    import { invoke } from '@tauri-apps/api/core';
    
    const nativeFetch: typeof fetch = async (input, init) => {
      const body = await invoke<string>('openai_proxy', {
        url: String(input),
        init,
      });
      return new Response(body, { status: 200 });
    };
    
    const agent = new Agent({
      instructions: "You are the desktop assistant",
      fetch: nativeFetch,   // implies dangerouslyAllowBrowser
      // no apiKey here — the key lives in Rust
    });
  3. Explicit override

    Force the browser guard on or off — useful in tests.

    typescript
    import { Agent } from 'praisonai';
    
    const agent = new Agent({
      instructions: "You are helpful",
      apiKey: process.env.OPENAI_API_KEY,
      dangerouslyAllowBrowser: true,
    });

How It Works

The Agent detects the runtime and merges the right options before constructing the OpenAI SDK.

Diagram
OpenAI SDKbuildOpenAIClientOptionsAgentUserOpenAI SDKbuildOpenAIClientOptionsAgentUsernew Agent({ apiKey, fetch? })options + runtime hintsdetect window / RN / custom fetchmerged options (± dangerouslyAllowBrowser)new OpenAI(mergedOptions)client ready (no throw)
RuntimeDetected asFlag added
Nodeprocess present, no windownone — behaviour unchanged
Browser / Electron rendererwindow + window.documentdangerouslyAllowBrowser: true
Embedded webview (Tauri)window + window.documentdangerouslyAllowBrowser: true
React Nativenavigator.product === 'ReactNative'dangerouslyAllowBrowser: true
Custom fetch suppliedany runtimedangerouslyAllowBrowser: true + injected fetch

When to use which option

Pick the option that matches where your code runs and how sensitive the key is.

Diagram

Node server

Browser / Electron / webview / RN

No — production mobile/desktop

Yes — internal tool / demo

Force behaviour for tests

Where does the code run?

Do nothing — Node path unchanged

Is the API key safe in the JS heap?

Pass a custom fetch → routes via native code

Auto-detected; nothing to pass

Set dangerouslyAllowBrowser explicitly


Configuration

Four knobs control credentials and transport across every runtime.

OptionTypeDefaultDescription
apiKeystringundefined (falls back to OPENAI_API_KEY)Per-agent OpenAI key.
baseURLstringundefinedPer-agent base URL for OpenAI-compatible endpoints.
fetchtypeof fetchundefinedCustom transport. Implies dangerouslyAllowBrowser.
dangerouslyAllowBrowserbooleanauto-detectedForce-enable the SDK’s browser guard. Auto-true in browser-like runtimes.

Precedence: an explicit dangerouslyAllowBrowser always wins — false even strips a pre-set flag. A custom fetch implies dangerouslyAllowBrowser: true, so a native bridge works even outside a webview.

buildOpenAIClientOptions Reference

TypeScript helper that merges runtime-aware options


Common Patterns

Tauri desktop app

Route every OpenAI request through a Rust command that owns the key.

typescript
import { Agent } from 'praisonai';
import { invoke } from '@tauri-apps/api/core';

const nativeFetch: typeof fetch = async (input, init) => {
  const body = await invoke<string>('openai_proxy', {
    url: String(input),
    init,
  });
  return new Response(body, { status: 200 });
};

const agent = new Agent({
  instructions: "You are the desktop assistant",
  fetch: nativeFetch,
});

await agent.chat("Summarize today's notes");

Electron renderer

Talk directly to OpenAI from the renderer — the guard is auto-added.

typescript
import { Agent } from 'praisonai';

const agent = new Agent({
  instructions: "You are the in-app assistant",
  apiKey: import.meta.env.VITE_OPENAI_KEY,
});

await agent.chat("Draft a release note");

React Native mobile app

navigator.product === 'ReactNative' is auto-detected.

typescript
import { Agent } from 'praisonai';

const agent = new Agent({
  instructions: "You are the mobile assistant",
  apiKey: MY_APP_CONFIG.openaiKey,
});

await agent.chat("What's on my agenda?");

Best Practices

Prefer injectable fetch over dangerouslyAllowBrowser in production

A custom fetch routes requests through native code, keeping the API key out of the JS heap. Reserve dangerouslyAllowBrowser for internal tools and demos.

Never bundle the API key into a shipped webview build

Anything in the JS bundle is readable. In production Tauri / Electron / mobile apps, keep the key in native code and expose only a proxy command.

Use a per-agent apiKey for multi-tenant apps

When multiple agents talk to different tenants or endpoints, set apiKey and baseURL per agent instead of relying on a single shared environment variable.

Guard process.env access in shared code

Reading process.env throws in webviews and React Native where process is absent. The SDK guards its own access; do the same in code you share across runtimes.


Related