Skip to main content
RapidDev - Software Development Agency
flutterflow-tutorials

How to Integrate a Custom CMS (Content Management System) with FlutterFlow

Integrate a headless CMS like Contentful, Strapi, or Sanity with FlutterFlow via REST API calls. Set up an API Group with your CMS base URL and authentication. Fetch content entries, map JSON responses to FlutterFlow UI elements, and render rich text using a flutter_html Custom Widget. Cache CMS content in Firestore via a webhook-triggered Cloud Function so your app reads from local cache for speed while the CMS remains the source of truth for content editors.

What you'll learn

  • How to configure FlutterFlow API Groups to fetch content from a headless CMS
  • How to map CMS JSON responses to FlutterFlow widgets with JSON path extraction
  • How to render rich text content using a flutter_html Custom Widget
  • How to cache CMS content in Firestore via webhooks for fast local reads
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Beginner8 min read25-35 minFlutterFlow Free+March 2026RapidDev Engineering Team
TL;DR

Integrate a headless CMS like Contentful, Strapi, or Sanity with FlutterFlow via REST API calls. Set up an API Group with your CMS base URL and authentication. Fetch content entries, map JSON responses to FlutterFlow UI elements, and render rich text using a flutter_html Custom Widget. Cache CMS content in Firestore via a webhook-triggered Cloud Function so your app reads from local cache for speed while the CMS remains the source of truth for content editors.

Connecting a Headless CMS to Your FlutterFlow App

Headless CMS platforms like Contentful, Strapi, and Sanity let non-technical editors manage content through a dashboard while your FlutterFlow app consumes it via API. This tutorial covers setting up API connections, mapping JSON responses to widgets, rendering rich text HTML, and caching content locally in Firestore for performance. Content editors work in the CMS dashboard while the app updates automatically.

Prerequisites

  • A FlutterFlow project with Firestore configured
  • An account on a headless CMS (Contentful, Strapi, or Sanity)
  • A CMS API key or access token for read access
  • Basic understanding of REST APIs and JSON response structure

Step-by-step guide

1

Set up a FlutterFlow API Group for your CMS

In FlutterFlow, go to API Calls and create a new API Group. Set the base URL to your CMS API endpoint: for Contentful it is https://cdn.contentful.com/spaces/{spaceId}/environments/master, for Strapi it is https://your-strapi-url.com/api, for Sanity it is https://{projectId}.api.sanity.io/v2021-10-21/data/query/production. Add a header for authentication: Contentful uses 'Authorization: Bearer {accessToken}', Strapi uses 'Authorization: Bearer {apiToken}', Sanity uses query parameters or bearer token. Create three API calls within the group: getEntries (list all entries of a content type), getEntryById (single entry by ID), and searchEntries (filtered query).

Expected result: A FlutterFlow API Group configured with your CMS base URL, authentication, and three API call definitions.

2

Create API calls to fetch content entries and single entries

For the getEntries call, set the path to the content type listing endpoint. Contentful: /entries?content_type={contentType}&limit=20&order=-sys.createdAt. Strapi: /{contentType}?sort=createdAt:desc&pagination[limit]=20. Sanity: ?query=*[_type=="{contentType}"][0..19]|order(_createdAt desc). Add contentType as a variable parameter. Test the API call in FlutterFlow's API tester and verify the response. For getEntryById, set the path to fetch a single entry: Contentful /entries/{entryId}, Strapi /{contentType}/{id}, Sanity ?query=*[_id=="{id}"][0]. Map the response fields in FlutterFlow's JSON path viewer to extract title, body, imageUrl, author, publishedDate.

Expected result: API calls fetch content lists and individual entries from the CMS with JSON paths mapped to extract title, body, and image fields.

3

Display CMS content in a list and detail page

Create a ContentListPage with a ListView. Add a Backend Query using the getEntries API call. Map each list item to a ContentCard Container showing: title Text (from JSON path to title field), excerpt Text (first 100 characters of body), featured image using the Image widget (from JSON path to image URL), and published date Text. Tapping a card navigates to a ContentDetailPage passing the entry ID as a route parameter. On the detail page, call getEntryById and display: title as H1 Text, author name, published date, featured image (full width), and body content. For plain text bodies, use a Text widget. For rich text bodies, use the flutter_html Custom Widget in the next step.

Expected result: A content list page shows CMS entries as cards and tapping opens a detail page with the full content.

4

Render rich text content with a flutter_html Custom Widget

Most headless CMS platforms return body content as HTML or rich text. Create a Custom Widget named RichContentRenderer that uses the flutter_html package to render HTML content. Pass the HTML string from the CMS response as a parameter. Configure custom tag styles for headings, paragraphs, lists, blockquotes, and code blocks to match your app's design theme. Handle images within the HTML by setting the customImageRenders to use CachedNetworkImage. Handle links by launching URLs via url_launcher when tapped. This widget converts CMS rich text into properly styled native Flutter elements.

rich_content_renderer.dart
1// Custom Widget: RichContentRenderer
2import 'package:flutter/material.dart';
3import 'package:flutter_html/flutter_html.dart';
4import 'package:url_launcher/url_launcher.dart';
5
6class RichContentRenderer extends StatelessWidget {
7 final String htmlContent;
8 final double width;
9 final double height;
10 const RichContentRenderer({
11 super.key,
12 required this.htmlContent,
13 required this.width,
14 required this.height,
15 });
16
17 @override
18 Widget build(BuildContext context) {
19 return SizedBox(
20 width: width,
21 child: Html(
22 data: htmlContent,
23 style: {
24 'h1': Style(
25 fontSize: FontSize(28),
26 fontWeight: FontWeight.bold,
27 margin: Margins.only(
28 bottom: 16, top: 24)),
29 'h2': Style(
30 fontSize: FontSize(22),
31 fontWeight: FontWeight.bold,
32 margin: Margins.only(
33 bottom: 12, top: 20)),
34 'p': Style(
35 fontSize: FontSize(16),
36 lineHeight: LineHeight(1.6),
37 margin: Margins.only(bottom: 12)),
38 'blockquote': Style(
39 backgroundColor: const Color(0xFFF5F5F5),
40 padding: HtmlPaddings.all(16),
41 margin: Margins.symmetric(
42 vertical: 12)),
43 'code': Style(
44 backgroundColor: const Color(0xFFF0F0F0),
45 fontFamily: 'monospace',
46 padding: HtmlPaddings.symmetric(
47 horizontal: 4, vertical: 2)),
48 },
49 onLinkTap: (url, _, __) {
50 if (url != null) launchUrl(Uri.parse(url));
51 },
52 ),
53 );
54 }
55}

Expected result: CMS rich text content renders as properly styled native elements with formatted headings, paragraphs, images, links, and code blocks.

5

Cache CMS content in Firestore via webhook for fast reads

Calling the CMS API on every page load is slow and may hit rate limits. Set up a caching layer: create a cms_content Firestore collection with fields matching your CMS content fields (title, body, imageUrl, author, publishedDate, contentType, cmsEntryId, lastSynced). Build a Cloud Function triggered by HTTP (webhook). Configure your CMS webhook to call this function URL whenever content is published or updated. The function receives the updated content, transforms it to match your Firestore schema, and writes or updates the document in cms_content. Update your FlutterFlow pages to read from Firestore cms_content instead of the CMS API. Keep the direct API calls as a fallback for cache misses.

Expected result: CMS content is cached in Firestore via webhook. The app reads from fast local Firestore while the CMS remains the editing source of truth.

Complete working example

FlutterFlow CMS Integration Setup
1API GROUP: CMS
2 Base URL: https://cdn.contentful.com/spaces/{spaceId}/environments/master
3 Headers: Authorization: Bearer {accessToken}
4
5 API Call: getEntries
6 GET /entries?content_type={contentType}&limit=20&order=-sys.createdAt
7 Response JSON paths:
8 items[].fields.title title
9 items[].fields.body body (HTML)
10 items[].fields.featuredImage.fields.file.url imageUrl
11 items[].sys.id entryId
12 items[].sys.createdAt publishedDate
13
14 API Call: getEntryById
15 GET /entries/{entryId}
16 Response JSON paths: fields.title, fields.body, etc.
17
18FIRESTORE CACHE:
19 cms_content/{docId}
20 cmsEntryId: String
21 contentType: String
22 title: String
23 body: String (HTML)
24 imageUrl: String
25 author: String
26 publishedDate: Timestamp
27 lastSynced: Timestamp
28
29CLOUD FUNCTION: cmsWebhook (HTTP triggered)
30 Receives: CMS webhook payload on publish/update
31 Action: Upsert cms_content doc by cmsEntryId
32 CMS Dashboard Settings Webhooks URL: function URL
33
34PAGE: ContentListPage
35 ListView
36 Backend Query: cms_content (Firestore, ordered by publishedDate desc)
37 ContentCard:
38 Row: Image (imageUrl) + Column (title, excerpt, date)
39 Tap ContentDetailPage(entryId)
40
41PAGE: ContentDetailPage (Route: entryId)
42 Column
43 Image (full width featured image)
44 Text (title, H1 style)
45 Text (author + date)
46 Custom Widget: RichContentRenderer(body HTML)
47
48CACHE STRATEGY:
49 1. App reads from Firestore cms_content (fast)
50 2. CMS publish triggers webhook Cloud Function Firestore update
51 3. Fallback: if cache miss, call CMS API directly

Common mistakes when integrating a Custom CMS (Content Management System) with FlutterFlow

Why it's a problem: Calling the CMS API directly on every page load without caching

How to avoid: Cache CMS content in Firestore via a webhook. The app reads from Firestore for speed. The webhook keeps the cache fresh when editors publish changes.

Why it's a problem: Rendering rich text HTML as plain text

How to avoid: Use the flutter_html package in a Custom Widget to properly render HTML as styled native Flutter elements with headings, paragraphs, links, and images.

Why it's a problem: Hardcoding CMS API keys in FlutterFlow frontend code

How to avoid: For read-only CMS access (content delivery API), public keys are acceptable. For management APIs, route all calls through Cloud Functions with keys stored in environment variables.

Best practices

  • Cache CMS content in Firestore via webhook rather than calling the API on every page load
  • Use flutter_html Custom Widget to properly render rich text content from the CMS
  • Set up JSON path mappings carefully using FlutterFlow's API response viewer
  • Keep CMS API keys for read-only delivery endpoints only in client-side code
  • Route management API calls through Cloud Functions for security
  • Use the CMS as the single source of truth for content while Firestore acts as a read cache
  • Configure webhooks to sync content automatically when editors publish changes

Still stuck?

Copy one of these prompts to get a personalized, step-by-step explanation.

ChatGPT Prompt

I want to integrate a headless CMS (Contentful, Strapi, or Sanity) with my FlutterFlow app. Show me how to set up FlutterFlow API Groups for the CMS, map JSON response fields to UI widgets, render rich text HTML with flutter_html, and cache content in Firestore via webhooks for performance. Include the data model and page layouts.

FlutterFlow Prompt

Create a content list page with a list view of card containers. Each card has an image on the left and a column with title text, short description text, and a date text on the right. Add a floating action button for refreshing content.

Frequently asked questions

Which headless CMS should I choose for FlutterFlow?

Contentful is the most popular with excellent documentation and generous free tier (25K records). Strapi is open-source and self-hostable. Sanity has real-time collaboration and a flexible schema. All three work with FlutterFlow via REST API.

Can non-technical editors update content without touching FlutterFlow?

Yes, that is the main benefit. Editors use the CMS dashboard to create, edit, and publish content. The webhook syncs changes to Firestore automatically. Editors never need to open FlutterFlow.

How do I handle images referenced in CMS content?

CMS platforms host images on their CDN. Contentful provides image URLs via the Asset API. Extract the image URL from the JSON response and use it in FlutterFlow Image widgets. For rich text inline images, flutter_html handles img tags automatically.

What happens if the CMS API is down?

Since your app reads from the Firestore cache, a CMS API outage does not affect users. They continue seeing cached content. New content published during the outage syncs when the CMS recovers and re-sends the webhook.

Can I use multiple content types from the same CMS?

Yes. Create separate API calls in the API Group for each content type (blog posts, product descriptions, FAQs, landing pages). Each content type can have its own FlutterFlow page template with appropriate widget layouts.

Can RapidDev help integrate a CMS with my FlutterFlow app?

Yes. RapidDev can set up headless CMS integration with content modeling, webhook-based syncing, rich text rendering, multilingual content, preview environments, and editorial workflow automation.

RapidDev

Talk to an Expert

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

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

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.