# How to Embed an Agent-Native Application Within an Existing App

> Embed an Agent-Native application in your app using the <EmbeddedApp> component. Securely communicate via a sandboxed iframe and message bridge for seamless integration.

- Repository: [Builder.io/agent-native](https://github.com/BuilderIO/agent-native)
- Tags: how-to-guide
- Published: 2026-06-29

---

**You can embed an Agent-Native application within another existing application by rendering the `<EmbeddedApp>` component from `@agent-native/embedding`, which creates a sandboxed iframe and exposes a type-safe, origin-validated message bridge for bidirectional communication.**

Agent-Native provides a lightweight embedding layer that lets you mount a full Agent-Native app, picker, or agent inside any existing React or plain-HTML host. According to the BuilderIO/agent-native source code, the `@agent-native/embedding` package is a thin re-export of the implementation found in [`packages/core/src/embedding/react.tsx`](https://github.com/BuilderIO/agent-native/blob/main/packages/core/src/embedding/react.tsx), giving you a secure iframe-based integration with support for fire-and-forget messages and typed request-response patterns.

## How Agent-Native Embedding Works

At its core, the embedding system renders an `<iframe>` that loads the remote Agent-Native app URL. The `EmbeddedApp` component in [`packages/core/src/embedding/react.tsx`](https://github.com/BuilderIO/agent-native/blob/main/packages/core/src/embedding/react.tsx) automatically appends `embedded=1` to the query string via `withEmbeddedAppParams` so the remote app knows to hide its own navigation chrome. All cross-frame traffic is wrapped in a typed **Agent-Native embed envelope** defined in [`packages/core/src/embedding/protocol.ts`](https://github.com/BuilderIO/agent-native/blob/main/packages/core/src/embedding/protocol.ts), which includes a `type` field such as `MESSAGE`, `REQUEST`, `RESPONSE`, `ERROR`, or `READY`, plus an optional `requestId` for correlated conversations.

### Key Source Files

- [`packages/embedding/src/react.tsx`](https://github.com/BuilderIO/agent-native/blob/main/packages/embedding/src/react.tsx) — Public package entry point that re-exports the core React component.
- [`packages/core/src/embedding/react.tsx`](https://github.com/BuilderIO/agent-native/blob/main/packages/core/src/embedding/react.tsx) — Full `EmbeddedApp` implementation that manages the iframe lifecycle, message routing, and request storage.
- [`packages/core/src/embedding/protocol.ts`](https://github.com/BuilderIO/agent-native/blob/main/packages/core/src/embedding/protocol.ts) — Defines envelope types, URL helpers like `embeddedAppOrigin`, and validation utilities.
- [`packages/core/src/embedding/bridge.ts`](https://github.com/BuilderIO/agent-native/blob/main/packages/core/src/embedding/bridge.ts) — Convenience functions for the embedded side to post back to the host.
- [`packages/embedding/README.md`](https://github.com/BuilderIO/agent-native/blob/main/packages/embedding/README.md) — Quick-start documentation and example snippets.

## How to Embed an Agent-Native Application in React

The simplest way to embed an Agent-Native application is to import the `EmbeddedApp` component and provide a `url` prop.

```tsx
import { EmbeddedApp } from "@agent-native/embedding";

function Host() {
  return (
    <EmbeddedApp
      url="https://assets.agent-native.com/picker"
      // optional: add custom query params or disable the default ?embedded=1
      // embed={false}
      onLoad={(ref) => {
        // fire-and-forget message to configure the picker
        ref.postMessage("configure", { accept: ["image/*"] });
      }}
      onMessage={(name, payload) => {
        if (name === "chooseImage") {
          console.log("User picked:", payload);
        }
      }}
      style={{ height: 500 }} // optional custom iframe styling
    />
  );
}

```

In [`packages/core/src/embedding/react.tsx`](https://github.com/BuilderIO/agent-native/blob/main/packages/core/src/embedding/react.tsx), the component derives the iframe origin from the URL using `embeddedAppOrigin` and uses it as the default `targetOrigin`. You can override this with `targetOrigin` or whitelist additional origins via `allowedOrigins`.

## Sending Fire-and-Forget Messages to the Embedded App

The host communicates with the embedded app through an imperative ref provided to the `onLoad` callback. Use `ref.postMessage(name, payload)` to send fire-and-forget events to the Agent-Native UI. The embedded app signals readiness by emitting a `READY` envelope, which the host receives through `onReady`, while general one-way messages arrive via `onMessage`.

## Request-Response Communication Between Host and Embedded App

For asynchronous operations that require an answer, the host can call `ref.request(name, payload, { timeoutMs })`. Internally, [`packages/core/src/embedding/react.tsx`](https://github.com/BuilderIO/agent-native/blob/main/packages/core/src/embedding/react.tsx) generates a unique correlation ID via `createEmbeddedAppRequestId` and stores the pending promise in a `Map`. The promise resolves when a `RESPONSE` envelope arrives or rejects on `ERROR` or timeout.

```tsx
import { useRef } from "react";
import { EmbeddedApp, type EmbeddedAppRef } from "@agent-native/embedding";

export function HostWithImperative() {
  const appRef = useRef<EmbeddedAppRef>(null);

  const generate = async () => {
    const result = await appRef.current?.request<string>(
      "GenerateBlogHero",
      { topic: "AI agents" },
      { timeoutMs: 60_000 },
    );
    console.log("Generated hero:", result);
  };

  return (
    <>
      <button onClick={generate}>Generate Hero</button>
      <EmbeddedApp
        url="https://assets.agent-native.com/blog-writer"
        ref={appRef}
        onReady={() => console.log("Embedded app ready")}
      />
    </>
  );
}

```

## Handling Inbound Requests from the Embedded Agent-Native App

The embedded app can also act as a client while the host acts as a server. Use the `onRequest` prop to handle inbound requests, return data directly, or throw an error to reject the call.

```tsx
import { EmbeddedApp } from "@agent-native/embedding";

function HostWithRequests() {
  return (
    <EmbeddedApp
      url="https://assets.agent-native.com/agent"
      onRequest={async (name, payload) => {
        if (name === "fetchUserData") {
          // Perform a server-side fetch or DB query here
          const user = await fetch("/api/user").then((r) => r.json());
          return user;
        }
        throw new Error(`Unsupported request ${name}`);
      }}
    />
  );
}

```

If you throw inside `onRequest`, the bridge sends an `ERROR` envelope back to the embedded app. This lets the embedded side catch the exception exactly like a failed network call.

## Communicating from the Embedded App Back to the Host

Inside the Agent-Native application running in the iframe, import the bridge helpers to send messages upward to the parent window.

```ts
import { sendEmbeddedAppMessage } from "@agent-native/embedding/bridge";

sendEmbeddedAppMessage("chooseImage", {
  url: "https://cdn.example.com/photo.png",
});

```

This helper lives in [`packages/core/src/embedding/bridge.ts`](https://github.com/BuilderIO/agent-native/blob/main/packages/core/src/embedding/bridge.ts) and wraps the payload in the standard `createAgentNativeEmbedEnvelope` format before calling `window.parent.postMessage`. It ensures that every payload conforms to the protocol expected by the host, regardless of how the embedded app is built.

## Security, Origins, and Cleanup

The embedding layer validates communication through origin checks. By default, `targetOrigin` is derived from the provided URL using `embeddedAppOrigin`, but you can explicitly set it or use `allowedOrigins` to support multiple trusted domains. All messages are scoped to these origins to prevent unauthorized cross-frame access.

When the `EmbeddedApp` component unmounts, all pending requests stored in the internal `Map` are automatically rejected. This prevents memory leaks and dangling promises if the user navigates away while requests are in flight.

## Summary

- Mount an Agent-Native app with `<EmbeddedApp>` from `@agent-native/embedding`, which renders a sandboxed iframe implemented in [`packages/core/src/embedding/react.tsx`](https://github.com/BuilderIO/agent-native/blob/main/packages/core/src/embedding/react.tsx).
- The iframe URL automatically receives `embedded=1` to hide native navigation chrome.
- Use `ref.postMessage()` for fire-and-forget events and `ref.request()` for promise-based request-response flows with configurable `timeoutMs`.
- Handle inbound requests with `onRequest`, and listen for readiness via `onReady`.
- Send messages from the iframe to the host with `sendEmbeddedAppMessage` from [`packages/core/src/embedding/bridge.ts`](https://github.com/BuilderIO/agent-native/blob/main/packages/core/src/embedding/bridge.ts).
- Origins are validated by default using `embeddedAppOrigin`, and pending promises are cleaned up on unmount to avoid memory leaks.

## Frequently Asked Questions

### Can I embed an Agent-Native app inside a non-React application?

Yes. While the official `@agent-native/embedding` package provides a React component in [`packages/embedding/src/react.tsx`](https://github.com/BuilderIO/agent-native/blob/main/packages/embedding/src/react.tsx), the underlying protocol in [`packages/core/src/embedding/protocol.ts`](https://github.com/BuilderIO/agent-native/blob/main/packages/core/src/embedding/protocol.ts) is standard `postMessage`. You can recreate the iframe and envelope logic in any framework or vanilla JavaScript.

### How does the embedded app know it is running inside an iframe?

The `EmbeddedApp` component automatically appends `embedded=1` to the iframe URL via `withEmbeddedAppParams`. The remote Agent-Native app reads this query parameter and conditionally hides its own navigation chrome.

### What happens to pending requests when the iframe unmounts?

All pending promises are automatically rejected. The `EmbeddedApp` component tracks requests in a `Map` and cleans them up during unmount to prevent memory leaks and unresolved promises.

### Is the host-to-embedded communication secure?

Yes. By default, messages are scoped to the iframe's origin via `targetOrigin` derived from `embeddedAppOrigin`. You can further restrict communication by passing an `allowedOrigins` array. All data is wrapped in typed envelopes created by `createAgentNativeEmbedEnvelope` for structured, validated exchanges.