Easy way to get user Feedback in Flutter
Gathering user feedback is very important for improving your Flutter application. In this post, we will talk about the feedback package, which makes it easy for users to send feedback. With this package, users can submit a screenshot along with a description. They can even draw on the screenshot to make their point clear. Let us see how this package can help you improve your application based on valuable user input.
Installing
To get started, we need to install the feedback package into our project. The installation process is simple. Just execute the following command: flutter pub add feedback
.
Once the command is executed, make sure to check your pubspec.yaml
file for the added dependencies. You should see the feedback package included in the dependencies section, like this:
dependencies:
feedback: ^2.6.0
flutter:
sdk: flutter
Capturing user feedback
Now that the package is successfully installed, let us begin with a basic implementation. The feedback package provides a BetterFeedBack
widget that requires a child widget. The widget should be the root of the widget tree. Specifically, it should be above any Navigator
widgets, including the navigator provided by the MaterialApp
widget, let us go over the example:
import 'package:feedback/feedback.dart';
import 'package:flutter/material.dart';
void main() => runApp(BetterFeedback(child: MyApp()));
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
void feedback() {
BetterFeedback.of(context).show((UserFeedback feedback) {
showDialog(
context: context,
builder: (BuildContext context) => SimpleDialog(
title: Column(
children: [
Text(feedback.text, style: TextStyle(fontSize: 24)),
SizedBox(height: 10),
Image.memory(feedback.screenshot, width: 250, height: 500),
],
),
),
);
});
}
return MaterialApp(
title: 'Feedback demo',
home: Scaffold(
appBar: AppBar(
title: Text('Feedback demo'),
),
body: Center(
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
child: Text('Give Feedback'),
onPressed: feedback,
),
],
),
),
),
),
);
}
}
In this code snippet, we start by wrapping the MyApp
widget with the BetterFeedback
widget. The BetterFeedback
widget is responsible for the feedback-capturing process.
Inside the MyApp
widget, we created a feedback
function. In this function
we call the BetterFeedback.of(context).show
which opens the feedback panel. When the feedback is submitted the function retrieves the feedback and displays it in a dialog using the showDialog
function. In the ShowDialog
we return a SimpleDialog
which contains a Column
widget that displays a Text
widget with the feedback text and a Image.memory
widget that displays the screenshot of the feedback. Be aware that the screenshot is returned as Uint8List
.
The MyApp
widget itself returns a Scaffold
widget that displays an ElavatedButton
. When the button is clicked it will invoke the feedback
function opening the feedback panel, see the GIF below:

Handling multiple pages
Now that we have covered the basic usage, let us take it a step further and see how the package works with applications that have multiple pages. Take a look at the following code snippet:
main.dart
import 'package:codeonwards_demo/custom_drawer.dart';
import 'package:feedback/feedback.dart';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BetterFeedback(
child: MaterialApp(
title: 'Feedback demo',
routes: {
'/profile-page': (context) => ProfilePage(),
},
home: HomePage(),
),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Feedback demo'),
),
drawer: CustomDrawer(),
body: SizedBox(),
);
}
}
class ProfilePage extends StatelessWidget {
const ProfilePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Profile page'),
),
body: SizedBox(),
);
}
}
In this code snippet, the MyApp
widget builds a MaterialApp
that is wrapped by the BetterFeedback
widget. It defines a title and one named route ("/profile-page"
) for the ProfilePage
. The HomePage
widget is returned on the home
property, which means that the HomePage
will have the default route name ("/"
).
The HomePage
widget displays a Scaffold
widget with an AppBar
widget containing the title "Feedback demo". It also includes a CustomDrawer
to enable navigation to different pages within the application.
The ProfilePage
widget also displays a Scaffold
widget with an AppBar
widget containing the title "Profile page." The body of both the HomePage
and ProfilePage
widgets are returning an empty SizedBox
widget.
custom_drawer.dart
import 'package:feedback/feedback.dart';
import 'package:flutter/material.dart';
class CustomDrawer extends StatelessWidget {
const CustomDrawer({super.key});
@override
Widget build(BuildContext context) {
return Drawer(
child: ListView(
children: [
ListTile(
leading: Icon(Icons.home),
title: Text('Home'),
onTap: () => Navigator.pushNamed(context, '/'),
),
ListTile(
leading: Icon(Icons.person),
title: Text('Profile page'),
onTap: () => Navigator.pushNamed(context, '/profile-page'),
),
ListTile(
leading: Icon(Icons.feedback),
title: Text('Feedback'),
onTap: () => BetterFeedback.of(context).show(
(UserFeedback feedback) => showDialog(
context: context,
builder: (BuildContext context) => SimpleDialog(
title: Column(
children: [
Text(
feedback.text,
style: TextStyle(fontSize: 24),
),
SizedBox(height: 10),
Image.memory(
feedback.screenshot,
width: 250,
height: 500,
),
],
),
),
),
),
),
],
),
);
}
}
In this code snippet, we created CustomDrawer
widget, which is used for navigation in the application. The CustomDrawer
widget also contains our feedback functionality. The build
method of the CustomDrawer
widget returns a Drawer
widget. The Drawer
is a material design component that provides a panel from the left side of the screen to display navigation options.
Within the Drawer
, a ListView
widget is used to organize the different navigation options vertically. The ListView
has three children, each represented by a ListTile
widget.
Home ListTile
leadingIcon
: A home icon (Icons.home
).title
: "Home".onTap
: When the user taps this item, it triggers theonTap
function, which usesNavigator.pushNamed(context, '/')
to navigate to the default route ("/"
). This means the user will be taken to the home page of the application when they tap the "Home" item in the drawer.
Profile ListTile
leadingIcon
: A person icon (Icons.person
).title
: "Profile page".onTap
: When the user taps this item, it triggers theonTap
function, which usesNavigator.pushNamed(context, '/profile-page')
to navigate to the named route for the profile page"/profile-page"
. This means the user will be taken to the profile page of the application when they tap the "Profile page" item in the drawer.
Feedback ListTile
leadingIcon
: A feedback icon (Icons.feedback
).title
: "Feedback".onTap
: When the user taps this item, it triggers theonTap
function, which uses the same functionality as the previous implementation to display the feedback panel, retrieve its values, and present them in a dialog.
When we run our application we will now have a multi-page application. As you can see within the feedback panel we are free to navigate through the application and can provide feedback on every page:

Conclusion
In this post, we explored the feedback package for Flutter, which offers a simple and user-friendly solution for gathering valuable user feedback. With this package, users can easily provide feedback by submitting screenshots with descriptions and even drawing on the images. We learned how to install the package and implement its basic usage, creating an easy feedback-capturing system within the application. Additionally, we discovered how to handle multiple pages using the feedback package, enabling navigation and feedback submission from various sections of the application.