Skip to main content
RapidDev - Software Development Agency

Ecwid

Connect FlutterFlow to Ecwid via two paths: embed the Ecwid storefront JavaScript in a WebView Custom Widget for instant working cart and checkout, or use FlutterFlow API Calls against Ecwid REST v3 for a fully native product catalog UI. The embedded WebView is the fastest route to a working store; the REST path requires proxying write calls through a Cloud Function to protect the secret_ token.

What you'll learn

  • How to embed the Ecwid JavaScript storefront in a FlutterFlow Custom Widget using webview_flutter for instant cart and checkout
  • Why the embedded WebView doesn't render in FlutterFlow's browser Preview and how to test it correctly
  • How to set up Ecwid REST v3 API Calls in FlutterFlow using your Store ID and Bearer token
  • Why the secret_ Ecwid token must be proxied through a Firebase Cloud Function and how to set that up
  • How to avoid mixing the embedded storefront and native REST data in the same checkout flow
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate17 min read30 minutes (WebView path) or 60 minutes (REST API path)E-commerceLast updated July 2026RapidDev Engineering Team
TL;DR

Connect FlutterFlow to Ecwid via two paths: embed the Ecwid storefront JavaScript in a WebView Custom Widget for instant working cart and checkout, or use FlutterFlow API Calls against Ecwid REST v3 for a fully native product catalog UI. The embedded WebView is the fastest route to a working store; the REST path requires proxying write calls through a Cloud Function to protect the secret_ token.

Quick facts about this guide
FactValue
ToolEcwid
CategoryE-commerce
MethodCustom Widget
DifficultyIntermediate
Time required30 minutes (WebView path) or 60 minutes (REST API path)
Last updatedJuly 2026

Two Ways to Build an Ecwid App in FlutterFlow

Ecwid, now part of Lightspeed's E-Series platform, stands out among e-commerce tools for FlutterFlow developers because it offers two genuinely different integration paths. The first — embedding the Ecwid JavaScript storefront in a WebView — gives you a fully working store with products, cart, and checkout already built and handled by Ecwid's servers. The second — connecting to Ecwid REST v3 — lets you design a completely custom native Flutter UI with full control over every pixel, but requires more setup and careful security handling.

The WebView embed path is ideal for founders who need a working store fast. Ecwid's free plan supports up to around five products (verify the current limit at ecwid.com/pricing), making it possible to build and test your app without paying anything. Paid tiers add more products, abandoned cart recovery, and analytics — check current pricing on Ecwid's website as plans change. The storefront is loaded via a script tag pointing to https://app.ecwid.com/script.js, which renders a complete Ecwid store including your product catalog, shopping cart, and payment checkout. The key limitation: this Custom Widget will show as blank in FlutterFlow's browser Preview panel — you must test on a physical device or in Run mode.

The REST v3 path (base URL https://app.ecwid.com/api/v3/{storeId}) is for teams who want a fully branded native experience with custom fonts, layouts, and animations. Read operations using a public_ token are lower-risk, but write operations — updating orders, products, customers — require a secret_ scoped token that must never be placed in a client-side API Call. Always route write calls through a Firebase Cloud Function proxy. Pick one path for checkout and stick with it: mixing the WebView cart with native REST data creates duplicate cart state that is very difficult to debug.

Integration method

Custom Widget

The primary path uses a FlutterFlow Custom Widget wrapping webview_flutter to embed the Ecwid JavaScript storefront directly in your app — giving you a full working cart and checkout in under 30 minutes. A secondary REST API path uses FlutterFlow API Calls against Ecwid's v3 REST API for a fully native product catalog, with write operations proxied through a Firebase Cloud Function to protect the secret_ token.

Prerequisites

  • An Ecwid account (free plan works for up to ~5 products; paid plan needed for larger catalogs — verify at ecwid.com/pricing)
  • Your Ecwid Store ID (numeric — found in Ecwid Control Panel under Settings → System Settings → Store ID)
  • Your Ecwid REST API token (Control Panel → Apps → Legacy API Keys, or via OAuth) — use public_ for read-only, secret_ for writes
  • A Firebase project on the Blaze plan (required for Cloud Functions with outbound HTTP calls) if you need write operations
  • A FlutterFlow project set up and ready to add Custom Widgets and API Calls

Step-by-step guide

1

Path A: Create a WebView Custom Widget embedding the Ecwid storefront

This is the fastest path to a working Ecwid store in your FlutterFlow app. In the FlutterFlow left nav, click Custom Code → + Add → Widget. Name it EcwidStore. In the Dependencies field, type webview_flutter and add the latest stable version (check pub.dev for the current version number — FlutterFlow will validate it). Do not run any terminal commands; FlutterFlow fetches the package automatically. In the Widget code editor, paste the Dart widget code below. Replace YOUR_STORE_ID with your numeric Ecwid Store ID. The widget loads a minimal HTML page containing Ecwid's script.js embed tag, which bootstraps the full storefront including product listings, cart management, and payment checkout inside the WebView. Set the Widget Parameters: add a width (double) and height (double) parameter so you can control the widget size from the FlutterFlow canvas. Back on your app page, open the Widget Panel (+ button in the top toolbar) and search for EcwidStore — drag it onto your page and set width to the full page width (use MediaQuery) and height to the remaining page height after any header/nav bars. CRITICAL: This widget will appear blank in FlutterFlow's browser-based Preview panel — webview_flutter does not render in the browser. Click the Run button (top-right, looks like a play icon) to open your app in Run mode, or download an APK to a physical Android device to see the full storefront load. The embedded Ecwid store handles its own cart state, products, and checkout — you do not need to connect any backend in FlutterFlow for this path to work.

ecwid_store_widget.dart
1import 'package:flutter/material.dart';
2import 'package:webview_flutter/webview_flutter.dart';
3
4class EcwidStore extends StatefulWidget {
5 const EcwidStore({
6 Key? key,
7 this.width,
8 this.height,
9 }) : super(key: key);
10
11 final double? width;
12 final double? height;
13
14 @override
15 _EcwidStoreState createState() => _EcwidStoreState();
16}
17
18class _EcwidStoreState extends State<EcwidStore> {
19 late final WebViewController _controller;
20
21 // Replace with your numeric Ecwid Store ID
22 static const String _storeId = 'YOUR_STORE_ID';
23
24 static const String _ecwidHtml = '''
25<!DOCTYPE html>
26<html>
27<head>
28 <meta name="viewport" content="width=device-width, initial-scale=1">
29 <style>body { margin: 0; padding: 0; }</style>
30</head>
31<body>
32 <div id="my-store-$_storeId"></div>
33 <div>
34 <script data-cfasync="false" type="text/javascript"
35 src="https://app.ecwid.com/script.js?$_storeId"
36 charset="utf-8"></script>
37 <script type="text/javascript">
38 xProductBrowser("categoriesPerRow=3","views=grid(3,3) list(10) table(20)",
39 "categoryView=grid","searchView=list","id=my-store-$_storeId");
40 </script>
41 </div>
42</body>
43</html>''';
44
45 @override
46 void initState() {
47 super.initState();
48 _controller = WebViewController()
49 ..setJavaScriptMode(JavaScriptMode.unrestricted)
50 ..loadHtmlString(_ecwidHtml);
51 }
52
53 @override
54 Widget build(BuildContext context) {
55 return SizedBox(
56 width: widget.width,
57 height: widget.height,
58 child: WebViewWidget(controller: _controller),
59 );
60 }
61}
62

Pro tip: The embedded Ecwid store uses Ecwid's own checkout flow including payment processing — you do not need to integrate Stripe or any payment gateway separately. Ecwid handles it.

Expected result: After testing in Run mode or on a physical device, you see the full Ecwid storefront with your products, shopping cart, and checkout flow embedded inside your FlutterFlow app.

2

Path B: Create an Ecwid API Group for native REST product data

If you want a fully native product catalog UI rather than an embedded WebView, you'll use Ecwid's REST v3 API directly from FlutterFlow's API Calls panel. First, locate your Store ID in the Ecwid Control Panel under Settings → System Settings → Store ID (it's a numeric ID, e.g. 12345678). Get your API token from Control Panel → Apps → Legacy API Keys — the public_ token is read-only and safe to use for product and category reads; the secret_ token has write access and must be kept server-side. In FlutterFlow, click API Calls in the left nav → + Add → Create API Group. Name it EcwidCatalog. For the Base URL, enter https://app.ecwid.com/api/v3 — note that your Store ID appears in the path of each individual call, not in the base URL. Leave Authentication empty for now. Add your first API Call inside the group: click + Add API Call, name it GetProducts, set Method to GET, and enter the endpoint as /{{storeId}}/products. Open the Variables tab inside the API Call and add two variables: storeId (String, default your Store ID number) and token (String, leave default empty). In the Headers section, add one header: Authorization with value Bearer {{token}}. Open the Response & Test tab, fill in your Store ID and public_ token, and click Test API Call. You should see a JSON response containing an items array of products. Click Generate JSON Paths to detect fields like $.items[0].id, $.items[0].name, $.items[0].price, $.items[0].thumbnailUrl.

api_group_config.json
1{
2 "API Group": "EcwidCatalog",
3 "Base URL": "https://app.ecwid.com/api/v3",
4 "Authentication": "None (Bearer token passed per-call via variable)",
5 "API Calls": [
6 {
7 "Name": "GetProducts",
8 "Method": "GET",
9 "Endpoint": "/{{storeId}}/products",
10 "Headers": {
11 "Authorization": "Bearer {{token}}"
12 },
13 "Variables": [
14 { "name": "storeId", "type": "String" },
15 { "name": "token", "type": "String" },
16 { "name": "limit", "type": "Integer", "default": 20 },
17 { "name": "offset", "type": "Integer", "default": 0 }
18 ]
19 },
20 {
21 "Name": "GetCategories",
22 "Method": "GET",
23 "Endpoint": "/{{storeId}}/categories",
24 "Headers": {
25 "Authorization": "Bearer {{token}}"
26 }
27 }
28 ]
29}
30

Pro tip: Store your Ecwid Store ID as an App State constant via App Settings → App Values (not as a literal in every API Call). This makes it easy to switch stores during development.

Expected result: The EcwidCatalog API Group appears in your API Calls panel, and the GetProducts call returns a JSON product list with fields you can map to Data Types.

3

Deploy a Cloud Function proxy for Ecwid write operations

If your app only needs to read products and categories for a browsing UI, you can skip this step and use your public_ token directly in API Call variables. However, if your app needs to update orders, manage products, or access customer data, those calls require a secret_ scoped token — and that token must never appear in a FlutterFlow API Call header where it would be compiled into the app binary. Create a Firebase Cloud Function that accepts requests from FlutterFlow and forwards them to Ecwid using the secret_ token stored in the function's environment. Go to the Firebase Console → Cloud Functions, enable the Blaze billing plan if needed, and deploy the proxy function below. Store your Ecwid Store ID and secret_ token as environment variables in the Firebase Console under Functions → Configuration. The Cloud Function accepts a path parameter (e.g. /orders, /products/{id}) and an optional request body for write operations. FlutterFlow calls the function URL and receives the Ecwid API response. Set up a separate FlutterFlow API Group (e.g. EcwidAdmin) targeting your Cloud Function URL for all write operations, and keep EcwidCatalog with the public_ token for all read operations. This separation keeps read-heavy screens fast (direct API calls) while securing writes (proxied through the function).

index.js
1const functions = require('firebase-functions');
2const axios = require('axios');
3
4exports.ecwidProxy = functions.https.onRequest(async (req, res) => {
5 res.set('Access-Control-Allow-Origin', '*');
6 res.set('Access-Control-Allow-Methods', 'GET, PUT, POST, DELETE, OPTIONS');
7 res.set('Access-Control-Allow-Headers', 'Content-Type');
8 if (req.method === 'OPTIONS') {
9 res.status(204).send('');
10 return;
11 }
12
13 const storeId = process.env.ECWID_STORE_ID;
14 const secretToken = process.env.ECWID_SECRET_TOKEN;
15 if (!storeId || !secretToken) {
16 res.status(500).json({ error: 'Ecwid credentials not configured' });
17 return;
18 }
19
20 // e.g. req.query.path = '/orders' or '/products/12345'
21 const path = req.query.path || '/orders';
22 const ecwidUrl = `https://app.ecwid.com/api/v3/${storeId}${path}`;
23
24 try {
25 const response = await axios({
26 method: req.method,
27 url: ecwidUrl,
28 headers: {
29 Authorization: `Bearer ${secretToken}`,
30 'Content-Type': 'application/json',
31 },
32 data: req.body || undefined,
33 params: req.query.path ? {} : req.query,
34 });
35 res.status(response.status).json(response.data);
36 } catch (error) {
37 const status = error.response?.status || 500;
38 res.status(status).json({ error: error.message });
39 }
40});
41

Pro tip: If you only need read-only access to orders and customer data (e.g. an order-tracking screen), you can use a public_ token directly in FlutterFlow API Calls — public_ tokens are read-only scoped. Only the secret_ token needs the Cloud Function proxy.

Expected result: The Cloud Function deploys and returns Ecwid order or product data when called with a path query parameter. A separate EcwidAdmin API Group in FlutterFlow targets the function URL.

4

Map Ecwid JSON to Data Types and build native product screens

With the API Calls working, create Data Types to represent Ecwid products and categories. Go to Data Types in the FlutterFlow left nav → + Add Data Type. Create an EcwidProduct type with fields: id (Integer), name (String), price (Double), thumbnailUrl (String), categoryId (Integer), inStock (Boolean), description (String). Create an EcwidCategory type with: id (Integer), name (String), imageUrl (String). Link these Data Types to your API Call responses: open GetProducts → Response & Test → use JSON Paths to map $.items[0].id → id, $.items[0].name → name, $.items[0].price → price, $.items[0].thumbnailUrl → thumbnailUrl, $.items[0].inStock → inStock. Build your product catalog page: add a ListView widget, bind it via Backend Query to EcwidCatalog → GetProducts (pass your Store ID from App Values and public_ token from a secure App State variable). Inside the ListView, add a Card with an Image (bound to thumbnailUrl), Text widgets for name and price, and an in-stock Badge (a Container with conditional color based on the inStock boolean). For the category filter, add a horizontal ListView above the product grid, bind it to GetCategories, and use a selected category App State variable to filter products — pass the selected categoryId as a query parameter to GetProducts. Remember: keep checkout on Ecwid's side. When a user taps a product to buy, use the Launch URL action to open the Ecwid product's direct URL (from the product JSON url field) in an in-app browser, or redirect to the embedded WebView checkout screen if you used Path A.

Pro tip: Do not try to rebuild Ecwid's checkout flow with native FlutterFlow widgets — payment processing, cart persistence, and order creation are handled by Ecwid's storefront. Opening the Ecwid product URL in an in-app browser is the cleanest checkout experience for the REST path.

Expected result: Your product catalog screen shows Ecwid products fetched from the REST API, organized by category, with images, names, prices, and in-stock badges — all rendered in native Flutter widgets.

5

Test on device and resolve WebView rendering issues

Before releasing your app, test both integration paths on real devices. For the WebView embed path (Path A): the widget is completely invisible in FlutterFlow's web-based Preview panel — this is expected behavior and not a bug. Click the Run button (top-right) to test in Run mode, which opens your app in a real browser or simulator. For the most accurate test, download the APK (Android) or use Xcode for iOS and install on a physical device. Verify that the Ecwid product grid loads correctly, the shopping cart updates when products are added, and the checkout flow completes without errors. For the REST API path (Path B): API Calls do work in Preview mode, so you can test data loading in the browser. However, verify on a real mobile device to check image loading performance and layout on small screens. Test on both Android and iOS since webview_flutter has some behavioral differences between platforms — specifically, JavaScript execution permissions and cookie handling for login sessions. Common device-specific issues: on iOS, ensure NSAppTransportSecurity is configured for HTTP/HTTPS in your Info.plist via FlutterFlow's Settings → App Settings → iOS Info.plist if you see connection failures. On Android, check that INTERNET permission is set in Settings & Integrations → Permissions → Internet Access. Mixing the two paths is the most common source of confusion: if you use the WebView cart for checkout, do not also build native cart state from REST API calls. Pick one source of truth for the cart and stick with it throughout your app.

Pro tip: If you see a blank white screen where the Ecwid storefront should appear on iOS, check that WebView JavaScript is enabled. In the EcwidStore Custom Widget Dart code, confirm JavaScriptMode.unrestricted is set on the WebViewController — without it, Ecwid's script.js cannot initialize the storefront.

Expected result: On a physical Android or iOS device, the Ecwid storefront (WebView path) or native product catalog (REST path) loads correctly, products display with images, and the cart or checkout flow works end-to-end.

Common use cases

Quick-launch mobile storefront for an existing Ecwid store

A boutique owner already running an Ecwid store embeds it in a FlutterFlow app using the WebView path. Customers browse products, add to cart, and complete checkout through the familiar Ecwid-hosted flow — all within a branded mobile wrapper with push notifications for order updates via OneSignal.

FlutterFlow Prompt

A mobile shopping app with a bottom navigation bar: Home screen with a featured products banner, a Store tab embedding the full Ecwid storefront in a WebView, and an Orders tab showing order history via Ecwid REST v3 read calls.

Copy this prompt to try it in FlutterFlow

Custom product catalog with native Flutter UI

A lifestyle brand wants a pixel-perfect product browsing experience that matches their app's design system. They use Ecwid REST v3 to fetch products and categories into FlutterFlow Data Types, build custom Card widgets with animations via Framer-style transitions in FlutterFlow, and redirect to the Ecwid-hosted checkout URL when the user taps Buy.

FlutterFlow Prompt

A product catalog screen with a horizontal category scroll at the top, a masonry grid of product cards below, each with image, title, price, and an Add to Cart button that opens the Ecwid checkout in an in-app browser.

Copy this prompt to try it in FlutterFlow

Store admin app for inventory and order management

A merchant builds an internal FlutterFlow app to manage their Ecwid store on the go — viewing orders, updating product stock levels, and searching customers. All read calls use the public_ token via FlutterFlow API Calls, and product update writes go through a Firebase Cloud Function proxy using the secret_ token.

FlutterFlow Prompt

An admin dashboard app with three tabs: Orders (list with status filter and search), Products (inventory list with stock count editor), and Customers (searchable customer list with order history).

Copy this prompt to try it in FlutterFlow

Troubleshooting

The EcwidStore Custom Widget shows a blank white screen in the FlutterFlow Preview panel

Cause: webview_flutter does not render in FlutterFlow's web-based browser Preview — this is a known limitation of the package in browser environments.

Solution: This is expected behavior and not a bug. Click the Run button (top-right in FlutterFlow) to test in Run mode, which renders the WebView correctly. Alternatively, download an APK and install on a physical Android device. The storefront will load correctly on real devices.

Ecwid REST API returns 403 Forbidden when calling /products or /orders

Cause: The Bearer token is incorrect, expired, or doesn't have the required scope for the endpoint being called. public_ tokens cannot access order or customer data.

Solution: Verify the token in Ecwid's Control Panel → Apps → Legacy API Keys. For order/customer endpoints, you need a secret_ scoped token — but this must go through a Cloud Function proxy, not directly in a FlutterFlow API Call header. For product and category reads, confirm the public_ token is being passed correctly in the Authorization header as 'Bearer [token]'.

XMLHttpRequest error when testing the Ecwid REST API Call in FlutterFlow Preview

Cause: Ecwid's API endpoints may block browser-origin requests (CORS) in FlutterFlow's web-based Preview mode. Native iOS/Android builds do not have this limitation.

Solution: Test the API Call in Run mode or on a device rather than in the browser Preview. Alternatively, route all Ecwid API calls through the Cloud Function proxy (which adds CORS headers), and test the proxy URL in the FlutterFlow API Call instead of the direct Ecwid endpoint.

Cart shows duplicate items or checkout totals are incorrect when mixing WebView and REST API data

Cause: The Ecwid WebView storefront manages its own cart state entirely within the embedded JavaScript environment. Attempting to also manage cart state from REST API calls creates two independent cart instances that conflict.

Solution: Pick exactly one source of truth for the cart: either the embedded WebView storefront handles everything (Path A), or your custom REST-based UI redirects to Ecwid's checkout URL for payment (Path B). Never try to merge the two cart states. Remove any native cart widget state management if you are using the WebView embed for checkout.

Best practices

  • Choose one integration path (WebView embed OR REST API) and commit to it — mixing the two cart systems creates duplicate state that is very difficult to debug.
  • Never place the secret_ Ecwid token in a FlutterFlow API Call header, even for development testing — use the public_ token for reads and the Cloud Function proxy for any write operations.
  • Store the Ecwid Store ID as an App State constant or App Values entry so it's set in one place and referenced consistently across all API Calls and the WebView widget.
  • Always test the WebView Custom Widget on a real device (Run mode or physical device) — it renders blank in FlutterFlow's browser Preview and this is expected behavior.
  • Use Ecwid's hosted checkout for payment rather than rebuilding checkout natively — Ecwid handles PCI compliance, payment processing, and order creation, which are complex and risky to replicate in a Flutter client.
  • Enable error handling in Image widgets displaying Ecwid product thumbnails — images can fail to load on slow connections and the fallback prevents a broken UI.
  • Cache product category data locally in App State between sessions since categories change infrequently — this speeds up screen loads and reduces API calls.
  • Test on both Android and iOS before shipping, as webview_flutter has subtle behavioral differences between platforms including JavaScript permissions and cookie handling.

Alternatives

Frequently asked questions

Does the Ecwid WebView storefront work on both iOS and Android?

Yes, webview_flutter supports both platforms. On iOS, ensure JavaScript is enabled in the WebViewController settings (JavaScriptMode.unrestricted) since Ecwid's storefront relies on JavaScript to initialize. On Android, make sure the INTERNET permission is enabled in FlutterFlow's Settings & Integrations → Permissions. Test on physical devices for both platforms before releasing.

Can I use Ecwid's free plan to build and test my FlutterFlow app?

Yes — Ecwid's free plan supports a limited number of products (verify the current limit at ecwid.com/pricing) which is enough to build and test your integration. The REST API and WebView embed both work on the free plan. You'll need a paid Ecwid plan for a full production store with more products, abandoned cart recovery, and analytics.

Can I handle payments inside my FlutterFlow app without redirecting to Ecwid's checkout?

Ecwid manages payment processing, PCI compliance, and order creation through its own checkout flow. Rebuilding this natively in FlutterFlow would require integrating a separate payment gateway (like Stripe) and manually creating orders via the Ecwid API — a significant added complexity. For most apps, redirecting to the Ecwid checkout URL or using the embedded WebView storefront is the right approach.

Why does my API Call return product data in Preview but not on the device?

Check that your device has internet access and that the Base URL in the API Group is correct. If you're using a Cloud Function proxy, confirm it's deployed and returning data by testing the function URL directly in a browser. On iOS physical devices, also verify that App Transport Security settings in your Info.plist allow HTTPS connections to app.ecwid.com.

Do I need to build my own cart UI if I use the REST API path?

The REST API path gives you product catalog data (names, prices, images, categories) but does not provide a client-side cart management API. You would need to manage cart state yourself in FlutterFlow App State, and redirect to Ecwid's hosted checkout URL or the WebView storefront when the user is ready to pay. For this reason, most FlutterFlow developers use the WebView embed for checkout even when building a custom product catalog with the REST API.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Integrations are where projects stall

We wire FlutterFlow integrations like this one every week — auth, webhooks, edge cases included. Fixed-price builds from $13K, delivered in 6–10 weeks.

Talk to an integration engineer

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.