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

How to Build a Virtual Whiteboard Feature in FlutterFlow

Build a collaborative whiteboard using a Custom Widget with Canvas and GestureDetector for freehand drawing. Store completed strokes as individual Firestore documents in a strokes subcollection with real-time listeners so all users see changes live. Implement a toolbar with pen, eraser, shapes, color picker, and stroke width controls. Add undo/redo via a local stack and export the canvas to PNG for sharing.

What you'll learn

  • How to build a Custom Widget with Canvas and GestureDetector for freehand drawing
  • How to store strokes as Firestore documents for real-time collaborative sync
  • How to implement pen, eraser, shapes, and text tools in a toolbar
  • How to add undo/redo functionality with a local action stack
  • How to export the whiteboard canvas as a PNG image for sharing
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Beginner7 min read35-45 minFlutterFlow Free+ (real-time collaboration requires Firestore)March 2026RapidDev Engineering Team
TL;DR

Build a collaborative whiteboard using a Custom Widget with Canvas and GestureDetector for freehand drawing. Store completed strokes as individual Firestore documents in a strokes subcollection with real-time listeners so all users see changes live. Implement a toolbar with pen, eraser, shapes, color picker, and stroke width controls. Add undo/redo via a local stack and export the canvas to PNG for sharing.

Building a Real-Time Collaborative Whiteboard in FlutterFlow

A virtual whiteboard requires a drawing canvas, a toolbar with multiple tools, real-time sync between users, and export capabilities. This tutorial builds each piece using a Custom Widget for the canvas, Firestore real-time listeners for collaboration, a local undo/redo stack, and RepaintBoundary for image export.

Prerequisites

  • A FlutterFlow project with Firestore and Firebase Authentication configured
  • Basic understanding of FlutterFlow Custom Widgets and Dart
  • Familiarity with GestureDetector and Canvas concepts
  • The flutter_drawing_board package or willingness to build a custom Canvas widget

Step-by-step guide

1

Set up the Firestore data model for boards and strokes

Create a boards collection with fields: name (String), createdBy (Reference to users), participants (Array of user References), createdAt (Timestamp), lastModifiedAt (Timestamp). Create a strokes subcollection under each board: boards/{boardId}/strokes with fields: type (String: pen/eraser/rectangle/circle/line/text), points (Array of Maps, each with x and y as Doubles — for freehand pen and eraser), color (String, hex like '#FF0000'), strokeWidth (Double), userId (Reference, who drew this stroke), timestamp (Timestamp), startPoint and endPoint (Maps with x, y — for shapes and lines), text (String — for text tool), fontSize (Double — for text tool). Each completed stroke is one document. Do not write individual points as separate documents.

Expected result: Each board has a strokes subcollection where each document represents one complete drawing action, enabling efficient real-time sync.

2

Build the drawing Canvas Custom Widget with GestureDetector

Create a Custom Widget named WhiteboardCanvas with parameters: boardId (String) and an Action Parameter onExportImage returning image bytes. Wrap a CustomPaint widget inside a GestureDetector. In the GestureDetector: onPanStart records the starting point, onPanUpdate adds the current touch position to a local currentPoints list and triggers a repaint, onPanEnd packages the completed stroke (type, points, color, strokeWidth) and writes it to the Firestore strokes subcollection, then clears currentPoints. The CustomPainter reads all stored strokes from a local list and draws each one: pen strokes as connected line segments using canvas.drawPath, eraser strokes as white-colored lines, shapes using drawRect or drawOval with the start and end points.

Expected result: Users can draw freehand strokes on the canvas that are rendered in real-time and saved to Firestore when the gesture completes.

3

Add real-time collaboration with Firestore listeners

In the Custom Widget's initState, set up a Firestore real-time listener on boards/{boardId}/strokes ordered by timestamp. When the snapshot changes, update the local strokes list with all stroke documents and trigger a repaint. This means every user with the board open sees new strokes appear in real-time as other users draw. To distinguish between the local user's in-progress stroke (which is being drawn but not yet saved) and other users' saved strokes, render the local currentPoints on top of the stored strokes in the CustomPainter. Color-code strokes by userId so participants can see who drew what (optional: show user avatar at the cursor position).

Expected result: Multiple users see each other's completed strokes appear in real-time as they draw on the same board.

4

Build the toolbar with pen, eraser, shapes, color, and width controls

Above the WhiteboardCanvas widget, add a horizontal Row toolbar. Include IconButtons for: pen (draw mode), eraser (white pen that covers existing strokes), rectangle (draw rectangles), circle (draw circles), line (straight lines), text (tap to place text). Below or in an expandable section, add a color palette: a Row of 8 Container circles (black, red, blue, green, orange, purple, pink, grey) where tapping sets the current color in Page State. Add a Slider for stroke width (range 1-20, default 3). Add undo and redo IconButtons. Store the current tool, color, and width in Page State and pass them to the Custom Widget as parameters.

Expected result: Users can switch between drawing tools, pick colors, adjust stroke width, and use undo/redo from a persistent toolbar.

5

Implement undo/redo and PNG export

For undo: maintain a local undoStack list of the last stroke document IDs created by the current user. On undo tap, take the last ID from the stack, delete that stroke document from Firestore, and push the stroke data onto a redoStack. On redo, recreate the stroke document and move it back to undoStack. Limit the undo stack to 50 actions. For export: wrap the CustomPaint in a RepaintBoundary with a GlobalKey. On the export button tap, use RenderRepaintBoundary.toImage(pixelRatio: 2.0) to capture the canvas as an image. Convert to PNG bytes using image.toByteData(format: ImageByteFormat.png). Pass the bytes through the onExportImage callback. The parent page can then upload to Firebase Storage or open the share sheet.

Expected result: Users can undo and redo their recent drawing actions, and export the whiteboard as a PNG image for sharing or saving.

Complete working example

FlutterFlow Virtual Whiteboard Setup
1FIRESTORE DATA MODEL:
2 boards/{boardId}
3 name: String
4 createdBy: Reference (users)
5 participants: Array of References (users)
6 createdAt: Timestamp
7 lastModifiedAt: Timestamp
8
9 boards/{boardId}/strokes/{strokeId}
10 type: String (pen | eraser | rectangle | circle | line | text)
11 points: Array of Maps [{ x: 120.5, y: 340.2 }, ...]
12 color: String (hex, e.g., '#FF0000')
13 strokeWidth: Double (e.g., 3.0)
14 userId: Reference (users)
15 timestamp: Timestamp
16 startPoint: Map { x, y } (for shapes/lines)
17 endPoint: Map { x, y } (for shapes/lines)
18 text: String (for text tool)
19 fontSize: Double (for text tool)
20
21CUSTOM WIDGET: WhiteboardCanvas
22 Parameters: boardId (String), currentTool (String),
23 currentColor (String), currentWidth (Double)
24 Action Parameters: onExportImage (Uint8List)
25 State: List<StrokeData> allStrokes, List<Offset> currentPoints,
26 List<String> undoStack, List<StrokeData> redoStack
27
28 Widget Build:
29 RepaintBoundary(key: _boundaryKey)
30 GestureDetector
31 onPanStart record start point
32 onPanUpdate add point to currentPoints, repaint
33 onPanEnd write stroke to Firestore, clear currentPoints
34 child: CustomPaint(painter: WhiteboardPainter(allStrokes, currentPoints))
35
36PAGE: WhiteboardPage
37 Column
38 Row (toolbar, height: 56)
39 IconButton (pen) set tool
40 IconButton (eraser) set tool
41 IconButton (rectangle) set tool
42 IconButton (circle) set tool
43 IconButton (line) set tool
44 IconButton (text) set tool
45 VerticalDivider
46 IconButton (undo) undo last stroke
47 IconButton (redo) redo last undo
48 VerticalDivider
49 IconButton (download) export PNG
50 Row (color palette)
51 8x Container circles (tappable, selected has border)
52 Row (stroke width)
53 Slider (min: 1, max: 20, value: currentWidth)
54 Expanded
55 WhiteboardCanvas (boardId, tool, color, width)

Common mistakes when building a Virtual Whiteboard Feature in FlutterFlow

Why it's a problem: Storing every individual point as a separate Firestore document during drawing

How to avoid: Collect points locally during the gesture. Only write one Firestore document per completed stroke (on gesture end) containing the full points array.

Why it's a problem: Not using RepaintBoundary for canvas export, trying to screenshot the entire screen

How to avoid: Wrap the CustomPaint widget in a RepaintBoundary with a GlobalKey. Use boundary.toImage() to capture just the drawing area.

Why it's a problem: Rendering all strokes by re-querying Firestore on every frame during active drawing

How to avoid: Maintain a local strokes list updated by a real-time Firestore listener. The CustomPainter reads from this local list. Only Firestore writes happen on gesture end.

Best practices

  • Write one Firestore document per completed stroke, not per individual point, to minimize writes
  • Use Firestore real-time listeners for collaboration — all users see strokes as they are saved
  • Keep the current in-progress stroke in local state (not Firestore) to ensure smooth drawing performance
  • Limit the undo stack to 50 actions to prevent unbounded memory growth
  • Use RepaintBoundary with a pixelRatio of 2.0 for high-quality PNG export
  • Add a loading indicator while the board's strokes load from Firestore on initial page open
  • Clear the board by deleting all stroke documents in a batch write rather than one at a time

Still stuck?

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

ChatGPT Prompt

I want to build a collaborative virtual whiteboard in FlutterFlow. Show me how to create a Custom Widget with Canvas and GestureDetector for drawing, store strokes in Firestore for real-time sync, and implement undo/redo with PNG export.

FlutterFlow Prompt

Create a drawing page with a toolbar at the top containing icons for pen, eraser, rectangle, circle, line, undo, redo, and download. Below the toolbar, add a row of 8 colored circles for color selection and a slider for stroke width. The rest of the page is the drawing canvas area.

Frequently asked questions

How many users can draw on the same whiteboard simultaneously?

Firestore real-time listeners handle 10-20 concurrent users well. Beyond that, write contention and listener overhead increase. For larger groups, batch stroke updates or use a dedicated real-time service.

Can I add a background image to the whiteboard?

Yes. In the CustomPainter, draw a background image using canvas.drawImage() before rendering the strokes. Pass the background image URL as a Custom Widget parameter.

How do I implement an eraser that actually removes parts of strokes?

The simplest approach draws white-colored strokes over existing content. For true erasure (removing intersecting stroke segments), you would need to compute path intersections — this is complex and rarely needed for whiteboard use cases.

Can I save and reload whiteboard sessions?

Yes. Since strokes are stored in Firestore, the board persists automatically. When a user reopens the board page, the real-time listener loads all existing strokes and renders them on the canvas.

How do I handle very large whiteboards with thousands of strokes?

Paginate the strokes query to load the most recent 500 strokes first. For older strokes, flatten them into a single background image periodically using a Cloud Function, reducing the number of individual strokes to render.

What if I need a full collaboration suite with whiteboard, chat, and video?

RapidDev has built collaborative workspace apps in FlutterFlow combining real-time whiteboards, video conferencing, chat, and document sharing for team productivity platforms.

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.