On this page · 12 sections
- What GenUI and A2UI actually are
- Why "UI as data, not code" is the core idea
- How the pieces fit: the GenUI architecture
- Build it: a minimal GenUI screen
- Add your own widgets to the catalog
- The A2UI wire format and data binding
- A2UI versus MCP Apps and ChatKit
- What to watch before you ship
- India-specific considerations
- FAQ
- How eCorpIT can help
- References
Summary. On December 15, 2025 Google made A2UI public, an open, Apache 2.0 protocol that lets an AI agent describe a user interface as declarative JSON instead of text. Flutter's GenUI SDK uses A2UI as its wire format so an agent can compose real Flutter widgets from your app's own catalog. The pitch: instead of a wall of chat text, a booking agent returns a date picker, a time selector, and a submit button that the user can tap. This guide covers how the pieces fit, working Dart code from the official docs, the "UI as data, not code" security model, a comparison with MCP Apps and OpenAI ChatKit, and the honest caveats: the genui package is still alpha, and PromptBuilder.chat() can emit a 3,000 to 5,000 token system prompt on every request, which at Gemini 3.5 Flash's roughly $1.50 per million input and $9.00 per million output tokens (May 2026) is a real cost at scale. Target reader: Flutter and mobile developers building AI features on top of Flutter 3.44.
A2UI ships at format version 0.8 with early client libraries for Flutter, Web Components, and Angular, and it renders through your existing widgets rather than an iframe. That last point is the whole design. Below is the shortest possible A2UI component an agent can send:
{
"id": "welcome-text",
"component": "Text",
"text": "Welcome to GenUI",
"variant": "h1"
}
What GenUI and A2UI actually are
GenUI, generative UI, is a paradigm where the model responds with real, interactive UI instead of prose. A2UI (Agent-to-UI) is the protocol underneath it: an open specification that defines how an agent and a client collaborate on the composition and state of an interface. Google's A2UI team describes it as a way to transmit UI that is "safe like data, but expressive like code."
The GenUI SDK for Flutter is the client-side orchestration layer. Per the official Flutter docs, it is a suite of packages that coordinates the flow of information between your user, your Flutter widgets, and an AI agent, using a JSON format to compose a UI from your existing widget catalog. As the user interacts, state changes flow back to the agent, which is the loop that turns a chat into an app screen. The SDK reflects Flutter 3.44 and, as of the docs update on June 26, 2026, the genui package is still in alpha.
The separation matters: A2UI defines the message format, GenUI is one renderer of it. The same A2UI JSON payload can be rendered by Lit, Angular, Flutter, and community renderers for Android Compose and Apple SwiftUI. Write the agent once, render it on every client.
Why "UI as data, not code" is the core idea
Historically, showing UI from a remote, untrusted agent meant shipping HTML or JavaScript and sandboxing it in an iframe, which is heavy and rarely matches your app's styling. A2UI takes a different route. Google's three design principles are worth stating plainly:
- Security first. A2UI is a declarative data format, not executable code. Your client keeps a catalog of trusted, pre-approved components (for example
Card,Button,TextField), and the agent can only request components from that catalog. That reduces the risk of UI injection because the model never ships runnable code.
- LLM-friendly and incrementally updateable. The UI is a flat list of components with ID references, which a model can generate and revise incrementally for progressive rendering.
- Framework-agnostic. A2UI separates UI structure from implementation. The agent sends a component tree plus a data model; your client maps it to native widgets.
For anyone who has fought an untrusted embed, the catalog model is the headline. The agent proposes; your client disposes. The same instinct drives our note on agentic browser and enterprise data-security controls: keep model output on the data side of the boundary, never the execution side.
How the pieces fit: the GenUI architecture
The genui package exposes a small set of classes. You wire them once and then talk mostly to Conversation.
| Component | What it does | You provide |
|---|---|---|
| SurfaceController | Holds the widget catalogs and manages generated UI surfaces | Your Catalog list |
| Catalog and CatalogItem | The set of widgets the agent may generate, each with a schema | Widget name, schema, builder |
| PromptBuilder | Builds the system prompt and the tools the agent can call | System instruction fragments |
| A2uiTransportAdapter | Parses A2UI messages and pipes model chunks in | An onSend handler |
| A2uiAgentConnector | Low-level connection to a remote A2A server | The server URI |
| Conversation | Orchestrates transport and controller; your main handle | The controller and transport |
| Surface | The widget that renders one agent-generated surface | A surface ID |
| DataModel | Observable store for dynamic UI state; drives data binding | Nothing; widgets bind by path |
There are three ways to connect an agent provider: Firebase AI Logic for a client-only app where Firebase manages the Gemini API key, GenUI A2UI for a client/server setup where the agent runs on a server, and a build-your-own adapter for any other LLM.
Build it: a minimal GenUI screen
Add the packages. For a client-only Firebase path:
$ dart pub add genui firebase_ai
Then create the controller, a prompt builder, and a conversation. This is the shape the docs use, trimmed to the essentials:
import 'package:genui/genui.dart';
import 'package:firebase_ai/firebase_ai.dart';
// 1. The catalog is the ONLY set of widgets the agent may generate.
final surfaceController =
SurfaceController(catalogs: [BasicCatalogItems.asCatalog()]);
// 2. The system prompt tells the model to answer in UI, not text.
final promptBuilder = PromptBuilder.chat(
catalog: BasicCatalogItems.asCatalog(),
systemPromptFragments: ['You are a helpful assistant.'],
);
// 3. Pick a model. The docs example uses gemini-3.5-flash.
final model = FirebaseAI.vertexAI().generativeModel(
model: 'gemini-3.5-flash',
systemInstruction: Content.system(promptBuilder.systemPromptJoined()),
);
// 4. Wire transport -> controller.
late final A2uiTransportAdapter transportAdapter;
transportAdapter = A2uiTransportAdapter(onSend: (message) async {
// stream model output back with transportAdapter.addChunk(...)
});
final conversation = Conversation(
controller: surfaceController,
transport: transportAdapter,
);
To render, listen to conversation.events for ConversationSurfaceAdded and build a Surface for each surface ID:
Surface(surfaceContext: surfaceController.contextFor(surfaceId));
For a client/server build, swap in genui_a2a and point A2uiAgentConnector at your A2A server:
final connector = A2uiAgentConnector(url: Uri.parse('http://localhost:8080'));
connector.stream.listen(surfaceController.handleMessage);
On iOS or macOS, add the com.apple.security.network.client entitlement so the app can make outbound requests, or the connection fails silently.
Add your own widgets to the catalog
The core catalog is fine for a demo. Real apps register their own widgets so the agent generates on-brand UI. A CatalogItem binds a name, a JSON schema, and a builder. Here is a RiddleCard, following the docs example:
import 'package:json_schema_builder/json_schema_builder.dart';
import 'package:genui/genui.dart';
final _schema = S.object(
properties: {
'question': S.string(description: 'The question part of a riddle.'),
'answer': S.string(description: 'The answer part of a riddle.'),
},
required: ['question', 'answer'],
);
final riddleCard = CatalogItem(
name: 'RiddleCard',
dataSchema: _schema,
widgetBuilder: (itemContext) {
final json = itemContext.data as Map<String, Object?>;
return Card(
child: Column(children: [
Text(json['question'] as String),
Text(json['answer'] as String),
]),
);
},
);
Register it, then tell the system prompt to use it by name:
final controller = SurfaceController(
catalogs: [BasicCatalogItems.asCatalog().copyWith(newItems: [riddleCard])],
);
The agent now knows one more move. Because the widget name and schema are yours, the model cannot generate anything outside that contract.
The A2UI wire format and data binding
genui centers on a DataModel, an observable store for UI state. Widgets bind to it by path, so when a bound value changes only the dependent widgets rebuild. An input widget such as a TextField bound to /user/name updates the model directly, and every widget on that path rebuilds. That reactive loop between the user, the UI, and the agent is the point of the whole SDK. It is the same server-driven-UI idea Flutter teams already know from patterns in our Flutter AI features with Gemini and the Dart MCP guide, now standardized as a protocol.
A2UI versus MCP Apps and ChatKit
A2UI is not the only agentic-UI approach shipping in 2026. The Model Context Protocol added MCP Apps on November 21, 2025, and OpenAI has ChatKit. They solve overlapping problems differently.
| Approach | How UI is delivered | Best for |
|---|---|---|
| A2UI (Google) | Declarative component blueprint rendered by your native widgets | Cross-platform, multi-agent meshes where the client keeps styling and security |
| MCP Apps | UI as a resource via a ui:// URI, usually pre-built HTML in a sandboxed iframe |
Tool-returned interfaces inside MCP hosts |
| OpenAI ChatKit | Integrated, optimized UI inside the OpenAI ecosystem | Teams standardizing on OpenAI |
Google's own framing is that A2UI is "native-first": instead of fetching an opaque payload for a sandbox, the agent sends a blueprint of native components, so the UI inherits your app's styling and accessibility. "A2UI was a great fit for Flutter's GenUI SDK because it ensures that every user, on every platform, gets a high quality native feeling experience," said Vijay Menon, Engineering Director for Dart at Google. A2UI also has day-zero support in AG UI and CopilotKit; "We're excited to provide day-0 compatibility between AG-UI and A2UI," said Atai Barkai, founder of CopilotKit and AG UI.
What to watch before you ship
Three caveats keep this out of production for many teams today.
First, it is alpha. The Flutter docs label the genui package experimental and "likely to change," and A2UI is at format 0.8. Expect breaking changes; pin versions and budget for churn.
Second, the system prompt is heavy. The docs warn that PromptBuilder.chat() can generate a system prompt of 3,000 to 5,000 or more tokens, which can exceed the context window of small or on-device models. That is also a cost line: Gemini 3.5 Flash lists at about $1.50 per million input tokens and $9.00 per million output as of May 2026, so a multi-thousand-token prompt on every turn adds up at volume. The docs suggest a compact custom prompt or passing only the schema fragments you need through systemPromptFragments.
Third, on-device limits. If you target an on-device LLM, the full schema prompt may not fit, so plan for a trimmed catalog. Teams weighing model cost against capability should read our LLM hybrid routing and API-spend decision framework before wiring a frontier model into every screen.
None of this is a reason to ignore A2UI. It is a reason to prototype now and productionize when the format stabilizes.
India-specific considerations
For Indian product teams, the client/server split has a data-protection angle. In the GenUI A2UI setup, user input travels to a remote agent that decides what UI to return, so if that input includes personal data you must account for the Digital Personal Data Protection Act, 2023 (DPDP): where the agent runs, what it retains, and whether processing has a lawful basis. The catalog model helps, because the client, not the remote agent, still owns rendering, branding, and accessibility.
The upside is real for teams shipping to a wide device range across Bharat. One agent can compose the right form for a feature phone-class Android and a flagship alike, using your own widget catalog, without a store update per layout change. Flutter teams already running the Flutter 3.44 production upgrade have the baseline to try GenUI behind a feature flag.
FAQ
How eCorpIT can help
eCorpIT (eCorp Information Technologies Private Limited), founded in 2021 in Gurugram, is a CMMI Level 5 and MSME-certified engineering organisation with senior-led Flutter and AI teams and partnerships across Google, AWS, and Microsoft. We help product teams evaluate generative UI safely: designing a trusted widget catalog, wiring the GenUI SDK to a server-side A2UI agent, keeping the client in control of branding and DPDP-aligned data handling, and shipping it behind a feature flag rather than betting a release on an alpha package. If you want a build-or-wait recommendation for your app, talk to our Flutter team.
References
- Introducing A2UI: an open project for agent-driven interfaces, Google Developers Blog (Dec 15, 2025)
_Last updated: July 26, 2026._