# Flutter GenUI Tutorial: Build an AI Shopping Assistant

> Learn to build an AI-powered Flutter shopping assistant using the GenUI SDK. 

- Source: https://verygood.ventures/blog/flutter-genui-shopping-assistant-tutorial/
- Published: 2026-02-27
- Author: Jorge Coca
- Tags: Flutter, Genui, Tutorial, Dart, Design, VGV

---

Flutter developers have done a lot to integrate AI into their apps, and somehow the best most of us have managed is replacing a search bar with a chatbot. The user asks a question, and the AI responds with a wall of text. That is not the experience anyone envisioned when they first heard "AI-powered app."

When I walked through this problem at the [Flutter SF Meetup hosted by SoFi](https://luma.com/5uzi5ws4?tk=W5IuOR) recently, the reaction confirmed what we have been seeing in our own projects at VGV: Flutter developers are ready to move past plain-text AI responses and into real, interactive interfaces that the AI itself assembles. At VGV, we have been building AI-powered Flutter experiences since before GenUI existed as a library. Projects like [Ask Dash, a generative AI Flutter app we built with Google](https://verygood.ventures/blog/how-we-built-it-ask-dash-a-generative-ai-flutter-application/), taught us the pattern early. When we saw the Flutter GenUI SDK, we recognized it immediately: this is how you go from an LLM that talks to one that build.

![__wf_reserved_inherit](/assets/images/blog/flutter-genui-shopping-assistant-tutorial/body-0.png)
*Image taken by Frank van Puffelen (puf) during the Flutter SF Meetup hosted by SoFi.*

This post is the beginner-friendly companion to that talk. You will get just enough context to understand what GenUI is, and then we will go straight into building a working shopping assistant with it. The full source is available in the [genui_shopping_assistant repository on Github](https://github.com/VGVentures/genui_shopping_assistant); clone it now if you want to follow along.

## Why Text Responses Are Not Enough

Most AI-powered apps today respond with plain text. A user asks "show me running shoes under $150" and gets a wall of text listing options. GenUI flips this: instead of text, the AI assembles real, interactive Flutter widgets (product cards, filters, carousels) on the fly, using your own design system. The user sees a rich UI, not a chat log.

![__wf_reserved_inherit](/assets/images/blog/flutter-genui-shopping-assistant-tutorial/body-1.png)
*GenUI Flutter shopping assistant — text response vs. interactive product cards generated by GenUI*

Before we build anything, it helps to understand the limitation GenUI is designed to fix.

## What Is The Flutter GenUI SDK?

At its core, GenUI does one thing:

> GenUI is a Flutter library that lets an AI build your app's UI in real time, using your widgets, your brand rules, and the user's context and intent to power the experience.

Three concepts are all you need to get started:

### 1. You Define A Widget Catalog

The AI can only compose from widgets you have explicitely registered: product cards, buttons, filters, and so on. Your brand stays intact. This is the key insight: the catalog is the contract between your app and the AI.

### 2. The AI Assembles The UI As JSON

The LLM does not generate Dart code. It returns structured data that GenUI deserializes into real Flutter widgets at runtime. This is the mechanism that powers the A2UI [(Agent-to-UI) protocol,](https://github.com/flutter/genui) a structured contract where the AI describes intent, and the client renders it natively.

![__wf_reserved_inherit](/assets/images/blog/flutter-genui-shopping-assistant-tutorial/body-2.png)
*Flutter GenUI SDK — AI-generated JSON deserialized into interactive Flutter widgets at runtime*

### 3. Interactions Feed Back To The AI

When the user taps, selects, or types, that state goes back to the LLM, which can refine the UI. This loop is what makes GenUI *generative* rather than just *dynamic*

![__wf_reserved_inherit](/assets/images/blog/flutter-genui-shopping-assistant-tutorial/body-3.png)
*GenUI Flutter interaction loop — user taps trigger state updates sent to the LLM, which refines the generative UI*

You can explore these concepts in depth in the [official GenUI SDK documentation](https://docs.flutter.dev/ai/genui) and the [GenUI SDK components and concepts reference](https://docs.flutter.dev/ai/genui/components). Note that the SDK is experimental and the API is still evolving. Treat it accordingly, and get yourself ready for breaking changes in future releases.

For a deeper look at how Flutter GenUI is being applied to real-world products, see how we are [redefining the digital booking experience with Generative UI at VGV](https://verygood.ventures/blog/redefining-the-digital-booking-experience-with-generative-ui/).

## Building The Shopping Assistant: A Step-By-Step Flutter GenUI Tutorial

The best way to understand how these three pieces fit together is to build something real. Here is how to get the shopping assistant running.

![__wf_reserved_inherit](/assets/images/blog/flutter-genui-shopping-assistant-tutorial/body-4.png)
*A screenshot of the Shopping Assistant demo powered by GenUI*

### Prerequisites

Before you start, make sure you have:

-   **Flutter SDK in the latest stable version:** the *genui* package requires Dart 3.9 or later, shipped with Flutter 3.35.
-   A **Firebase project** with [**Firebase AI Logic**](https://firebase.google.com/products/firebase-ai-logic) enabled. While you can run this experience with a *Spark* free plan, a *Blaze* plan is recommended, as the token consumption limit will be more generous.
-   Clone the V[GV genui_shopping_assistant repository from Github](https://github.com/VGVentures/genui_shopping_assistant), run *flutter pub get,* and finish the connection with Firebase running *flutterfire configure.*

**Note on API stability:** the *genui package is in alpha (v0.7.0 when this article is posted). The API is subject to breaking changes between releases. This is expected for an experimental SDK at this stage. Check the* [*flutter/genui repository*](https://github.com/flutter/genui) *for the latest release notes before starting****.***

### Define Your Widget Catalog

A **Catalog** is a collection of **CatalogItem** objects that tells the AI exactly which widgets it can compose. Think of it as the contract between your app and the AI: if a widget is not in the catalog, the AI cannot use it. Your design system is enforced at runtime.

Each **CatalogItem** requires three things: a **name,** a **dataSchema** (defined with [json_schema_ builder](https://pub.dev/packages/json_schema_builder)) that tells the AI what data the widget expects, and a **widgetBuilder** function that turns data into a real Flutter widget.

Here is a simplified product card entry from the shopping assistant:

```dart
import 'package:genui/genui.dart';
import 'package:json_schema_builder/json_schema_builder.dart';

// The schema tells the AI what data a ProductCard expects.
// Mark required fields explicitly so the AI produces valid data.
final _productSchema = S.object(
  properties: {
    'name': S.string(description: 'Product display name.'),
    'price': S.number(description: 'Price in USD.'),
    'imageUrl': S.string(description: 'URL of the product image.'),
  },
  required: ['name', 'price', 'imageUrl'],
);

final productCard = CatalogItem(
  name: 'ProductCard',
  dataSchema: _productSchema,
  widgetBuilder: ({
    required data,
    required id,
    required buildChild,
    required dispatchEvent,
    required context,
    required dataContext,
  }) {
    final json = data as Map<String, Object?>;
    // Build and return your ProductCard widget here,
    // using json['name'], json['price'], json['imageUrl'].
  },
);
```

To register this item alongside the built-in GenUI core widget, pass it to **A2uiMessageProcessor:**

```dart
_processor = A2uiMessageProcessor(
  // CoreCatalogItems includes GenUI's built-in widgets.
  // copyWith appends your custom items without replacing the core set.
  catalogs: [CoreCatalogItems.asCatalog().copyWith([productCard])],
);
```

Now that the catalog is defined, we need to connect it to an LLM.

### Set Up The LLM Connection

The **ContentGenerator** is the bridget between your Flutter app and the AI. It decouples your app from a specific LLM provider, which matters when the model landscape is moving fast. For this tutorial, we will use **FirebaseAiContentGenerator**.

```dart
/// Creates and configures a [FirebaseAiContentGenerator] backed by Firebase AI
/// (Gemini 2.5 Flash).
///
/// The catalog schema is automatically sent to the AI via tool definitions.
/// History and state management are handled by [GenUiConversation].
FirebaseAiContentGenerator buildFirebaseAiContentGenerator() {
  return FirebaseAiContentGenerator(
    catalog: shoppingCatalog,
    systemInstruction:
        shoppingSystemInstructions + GenUiPromptFragments.basicChat,
  );
}
```

![__wf_reserved_inherit](/assets/images/blog/flutter-genui-shopping-assistant-tutorial/body-5.png)
*Flutter GenUI ContentGenerator — GoogleGenerativeAiContentGenerator and FirebaseAiContentGenerator bridging Flutter and the LLM*

With the LLM connected, it is time to wire everything together.

### Wire It Together And Run

The final step is creating a **GenUiConversation**, connecting it to the processor and content generator, and embedding a **GenUiSurface** in your widget tree. **GenUiConversation** is the primary facade that manages the back and forth between your app and the AI.

```dart
@override
void initState() {
  super.initState();
  _processor = A2uiMessageProcessor(
    catalogs: [CoreCatalogItems.asCatalog().copyWith([productCard])],
  );
  _conversation = GenUiConversation(
    a2uiMessageProcessor: _processor,
    contentGenerator: contentGenerator,
    // Track which UI surfaces the AI creates and removes.
    onSurfaceAdded: (update) =>
        setState(() => _surfaceIds.add(update.surfaceId)),
    onSurfaceDeleted: (update) =>
        setState(() => _surfaceIds.remove(update.surfaceId)),
  );
}

@override
void dispose() {
  // Always dispose the conversation to avoid resource leaks.
  _conversation.dispose();
  super.dispose();
}

// In your build method, render each surface:
GenUiSurface(
  host: _conversation.host,
  surfaceId: surfaceId,
)

// To send a user prompt:
_conversation.sendRequest(
  UserMessage.text('Show me running shoes under \$150'),
);
```

Launch the app, type a prompt like *"Show me running shoes under $150",* and watch GenUI assemble a product browsing experience from your catalog widgets. The AI reads your catalog, generates a JSON layout referencing **ProductCard** and other registered widgets, and GenUI deserializes it into your actual Flutter components.


Check the [genui package on pub.dev](https://pub.dev/packages/genui) for the current version and changelog.

## Where To Go From Here

You just built a working AI shopping assistant that renders real Flutter widgets from natural-language prompts. No chat bubbles, no text walls — just an actual product browsing experience composed by the AI from your own design system.

Here are a few directions to explore next:

-   **Extend your catalog:** try adding a price filter chip, a product comparison view, or a checkout summary widget. Each new *CatalogItem* expands what the AI can compose, and because the catalog is the contract, your brand controls stay intact.
-   **Try a different LLM provider:** implement a custom *ContentGenerator* that connects to a different model. The abstraction is there specifically because the model landscape will keep changing.
-   **Explore the official docs:** the [GenUI SDK getting started guide](https://docs.flutter.dev/ai/genui/get-started) covers advanced topics including the A2UI protocol, streaming AI updates, and custom *ContentGenerator* implementations.
-   **See GenUI in a production context:** read how [VGV is redefining the digital booking experience with generative UI](https://verygood.ventures/blog/redefining-the-digital-booking-experience-with-generative-ui/), or explore our [GenUI solutions resource page](https://verygood.ventures/resources/genui/) for a business-oriented perspective on what this technology enables across retail, travel, banking, and QSR.

This kind of problem (making AI a native part of your product's UX layer, not just a featured bolted on) is exactly where we focus at VGV. We have shipped [AI-powered Flutter experiences with Google](https://verygood.ventures/blog/the-shortest-path-to-ai-everywhere-is-flutter/) across industries, and we have been working with Flutter since its early days. If you are thinking through what GenUI means for your product, [we would be glad to think through it with you](https://verygood.ventures/contact-us/).
