SurveySparrow's flutter SDK lets you collect feedback at various touchpoints from your mobile app users. You can easily embed surveys in your mobile app with a few lines of code. This documentation walks you through the possibilities of the SDK before you begin integrating the mobile SDK with your app.
How it works?
You can install the SDK on Xcode or Android Studio and configure when you want to invoke the survey. Based on those conditions, you will be able to call the survey when a particular condition is met. For instance, let’s say your app lets people book a cab (like Uber or Lyft). You may want to display feedback surveys at after a trip is complete. You can easily do that with our SDK.
Steps to get started with the SDK
- Create a free account on Build better experiences, the right way | SurveySparrow and build a sample classic survey. You can also use our templates to get started easily. Please note that only these question types are supported for the flutter SDK: Opinion Scale, Text, Rating, Welcome page, Thank you page, Yes or No, Multiple Choice, Phone Number, Email.
- After building the survey, navigate to the “Share“ window. Click on “Mobile SDK“ and copy the access token. You will need this access token to call the survey.
- Copy the URL of your account (*.surveysparrow.com) and keep it handy.
Supported versions
- Android minSdkVersion >= 21
- IOS version >= 11.0
Installation:
To install the SDK, simply run this command:
$ flutter pub add surveysparrow_flutter_sdk
Getting started
Check SurveySparrow Flutter Sdk documentation for in-depth instructions on configuring and customization SurveySparrow Flutter Sdk can be used in two ways either you can use the in-built survey modal for collecting the feedback or you can use your own UI and use the helper functions to collect and submit responses
Examples
Example 1
import 'package:flutter/material.dart';
import 'package:surveysparrow_flutter_sdk/surveysparrow.dart';
class SurveyScreen extends StatelessWidget {
const SurveyScreen({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("SurveySparrow"),
leading: IconButton(
icon: Icon(Icons.arrow_back, color: Colors.black),
onPressed: () => Navigator.of(context).pop(),
),
),
body: Builder(
builder: ((context) => Container(
width: double.infinity,
height: double.infinity,
child: SurveyModal(
token: 'tt-0daa18',
domain: 'sachin.officesparrow.com',
onNext: (val) {
print("Currently collected answer ${val} ");
},
onError: () {
Navigator.pop(context);
},
onSubmit: (val) {
print("All collected answer ${val} ");
Future.delayed(const Duration(milliseconds: 500), () {
Navigator.pop(context);
});
},
),
)),
),
);
}
}
Example 2 (Advanced Customization)
import 'package:flutter/material.dart';
import 'package:surveysparrow_flutter_sdk/surveysparrow.dart';
class SurveyScreen extends StatelessWidget {
const SurveyScreen({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("SurveySparrow"),
leading: IconButton(
icon: Icon(Icons.arrow_back, color: Colors.black),
onPressed: () => Navigator.of(context).pop(),
),
),
body: Builder(
builder: ((context) => Container(
width: double.infinity,
height: double.infinity,
child: SurveyModal(
token: 'tt-0daa18',
domain: 'sachin.officesparrow.com',
variables: const {
"custom_name": "surveysparrow",
"custom_number": "2"
},
firstQuestionAnswer: FirstQuestionAnswer(
pageNumber: 1, // number of pages to skip when the user takes the survey
answers: [
Answer(
opnionScale: CustomOpinionScale(
key: 22864,
data: 3,
timeTaken: 1,
skipped: false,
),
),
Answer(
rating: CustomRating(
key: 22865,
data: 3,
timeTaken: 1,
skipped: false,
),
),
Answer(
multipleChoice : CustomMultiChoice(
key: 22866,
data: [20862, 20864],
timeTaken: 1,
skipped: false,
),
)
],
),
customSurveyTheme: CustomSurveyTheme(
question: Question(
questionNumberFontSize: 20.0,
questionHeadingFontSize: 30.0,
questionDescriptionFontSize: 20.0),
logo: Logo(fontSize: 20.0),
bottomBar: BottomBar(navigationButtonSize: 50.0),
nextButton:
NextButton(fontSize: 20.0, width: 120.0, iconSize: 30.0),
email: Email(fontSize: 30.0),
skipButton: SkipButton(fontSize: 20.0),
rating: Rating(
svgHeight: 80,
svgWidth: 80,
customRatingSvgUnselected:
'<svg width="23" height="22" viewBox="0 0 23 22" fill="none" xmlns="http://www.w3.org/2000/svg"><path clip-rule="evenodd" d="m11.5 17.5-5.878 3.09 1.123-6.545L1.989 9.41l6.572-.955L11.5 2.5l2.939 5.955 6.572.955-4.756 4.635 1.123 6.545L11.5 17.5Z" stroke="#007AFF" stroke-width="1.5"/></svg>',
customRatingSvgSelected:
'<svg width="23" height="21" viewBox="0 0 23 21" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="m11.5 16.5-5.878 3.09 1.123-6.545L1.989 8.41l6.572-.955L11.5 1.5l2.939 5.955 6.572.955-4.756 4.635 1.123 6.545L11.5 16.5Z" fill="#007AFF" stroke="#007AFF"/></svg>',
),
yesOrNo: YesOrNo(
outerContainerHeight: 200.0,
outerContainerWidth: 180.0,
svgHeight: 70.0,
svgWidth: 70.0,
fontSize: 20.0,
circleFontIndicatorSize: 30.0),
phoneNumber: PhoneNumber(
countryPickerWidth: 100.0,
countryPickerHeight: 80.0,
fontSize: 28.0),
opinionScale: OpinionScale(
labelFontSize: 20,
numberFontSize: 18,
runSpacing: 28.0,
),
welcome: WelcomePageTheme(
headerFontSize: 30.0,
imageDescriptionFontSize: 25.0,
descriptionFontSize: 30.0,
imageHeight: 350,
imageWidth: 550,
buttonFontSize: 30.0,
buttonWidth: 500.0,
buttonIconSize: 44.0,
),
thankYouPage: ThankYouPageTheme(
headerFontSize: 30.0,
imageDescriptionFontSize: 25.0,
descriptionFontSize: 30.0,
imageHeight: 550,
imageWidth: 650,
buttonFontSize: 30.0,
buttonWidth: 500.0,
buttonIconSize: 44.0,
visibilityTime: 5000,
),
),
onNext: (val) {
print("Currently collected answer ${val} ");
},
onError: () {
Navigator.pop(context);
},
onSubmit: (val) {
print("All collected answer ${val} ");
Future.delayed(const Duration(milliseconds: 500), () {
Navigator.pop(context);
});
},
),
)),
),
);
}
}
Example 3 (Preloading survey and using it)
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:flutter/material.dart';
import 'package:surveysparrow_flutter_sdk/surveysparrow.dart';
Future<Map<dynamic, dynamic>> fetchSurvey() async {
var domain = "sachin.officesparrow.com"; // use your domain
var token = "tt-0daa18"; // use your mobile sdk share token
var url = 'https://${domain}/api/internal/sdk/get-survey/${token}';
final response = await http.get(Uri.parse(url));
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
final parsedJson = jsonDecode(response.body);
return parsedJson;
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load survey');
}
}
class PreLoadedSurveyScreen extends StatelessWidget {
const PreLoadedSurveyScreen({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("SurveySparrow"),
leading: IconButton(
icon: Icon(Icons.arrow_back, color: Colors.black),
onPressed: () => Navigator.of(context).pop(),
),
),
body: FutureBuilder(
future: fetchSurvey(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
return Container(
width: double.infinity,
height: double.infinity,
child: SurveyModal(
token: 'tt-0daa18',
domain: 'sachin.officesparrow.com',
variables: const {
"custom_name": "surveysparrow",
"custom_number": "2"
},
survey: snapshot.data,
onNext: (val) {
print("Currently collected answer ${val} ");
},
onError: () {
Navigator.pop(context);
},
onSubmit: (val) {
print("All collected answer ${val} ");
Future.delayed(const Duration(milliseconds: 500), () {
Navigator.pop(context);
});
},
),
);
} else {
return Container(
child: const Text("Loading"),
);
}
},
),
);
}
}
Handle Survey Validation
Use the below snippet in any component which requires a survey validation before popping up
import 'package:surveysparrow_flutter_sdk/helpers/survey.dart';
late Future<Map<dynamic, dynamic>> surveyValidation =
handleSurveyValidation(this.token, this.domain);
// response will be { "active": true, "reason": "" }
// if the active is true, the survey is valid, if the active is false we can get the reason for survey validation fail in reason
Customizations For SurveyModal
You can also customize the appearance of each question type with these functions:
Question font customizations:
question questionNumberFontSize(double)
DESC -> question number font size
questionHeadingFontSize(double)
DESC -> question header font size
questionDescriptionFontSize(double)
DESC -> question description font size
Skip button customizations:
fontSize(double)
DESC -> skip button font size
Animation Direction customizations:
animationDirection(String)
DESC -> animation direction of question value can be horizontal or vertical
Bottom Bar customizations:
padding(double)
DESC -> bottom bar padding
navigationButtonSize(double)
DESC -> bottom bar navigation button size
Next button customizations:
fontSize(double)
DESC -> the font size that appears inside the button
width(double)
DESC -> width of the next button
iconSize(double)
DESC -> icon size that is displayed in next button
Logo customization:
bannerHeight(double)
DESC -> banner height that is displayed for showing the logo
fontSize(double)
DESC -> fontsize of the logo name
logoHeight(double)
DESC -> logo height of the logo in banner
logoWidth(double)
DESC -> logo width of the logo in banner
Rating question type customizations:
hasNumber(bool)
DESC -> can be used to toggle the number that is shown below rating
svgHeight(double)
DESC -> height of the rating svg
svgWidth(double)
DESC -> width of the rating svg
customRatingSVGUnselected(double)
DESC -> custom unselected svg to display instead of default surveysparrow svg
customRatingSVGSelected(double)
DESC -> custom selected svg to display instead of default surveysparrow svg
Opinion scale question type customizations:
outerBlockWidth(double)
DESC -> opnionScale outer block width
outerBlockHeight(double)
DESC -> opnionScale outer block height
innerBlockWidth(double)
DESC -> opnionScale inner block width
innerBlockHeight(double)
DESC -> opnionScale inner block height
labelFontSize(double)
DESC -> the font size of most Likely, least Likely labels
numberFontSize(double)
DESC -> the font size of number inside the block
runSpacing(double)
DESC -> run spacing for the blocks
positionedLabelTopValue(double)
DESC -> labels top value offset
Yes or no question type customizations:
svgHeight(double)
DESC -> yesOrNo svg icon height
svgWidth(double)
DESC -> yesOrNo svg icon width
customSVGUnselected( String )
DESC -> custom unselected svg to display instead of default surveysparrow svg
customSVGSelected( String )
DESC -> custom selected svg to display instead of default surveysparrow svg
outerContainerWidth ( double )
DESC -> outer container size of yes or no question card
outerContainerHeight ( double )
DESC -> outer container height of yes or no question card
circularFontIndicatorSize ( double )
DESC -> circle Font Indicator Size size of yes or no
fontSize(double)
DESC -> font size used
Text and Email question type customizations:
fontSize(double)
DESC -> font size of input
textFieldWidth(double)
DESC -> width of text field
Multiple choice question type customizations:
choiceContainerWidth( String)
DESC -> choice Container Width to be set
choiceContainerHeight( String)
DESC -> choice Container Height to be set
fontSize(Double)
DESC -> font size of choice text
circularFontContainerSize(Double)
DESC -> circular Font Container Size of choice bar
otherOptionTextFieldHeight( String)
DESC -> other Option Text Field Height to be set
otherOptionTextFieldWidth( String)
DESC -> other Option TextField Width to be set
otherOptionTextFontSize( String)
DESC -> other Option Text Font Size to be set
Phone number question type customizations:
defaultcountryCode( String)
DESC -> default country code to be set
fontSize(Double)
DESC -> font size of input fields
countryPickerWidth(double)
DESC -> width of country Picker Width
countryPickerHeight(double)
DESC -> height of country Picker Height
countryCodeInputWidth(double)
DESC -> width of country CodeInput Width
countryCodeInputHeight(double)
DESC -> height of country CodeInput Height
phoneNumberInputWidth(double)
DESC -> width of country CodeNumber Input Width
phoneNumberInputHeight(double)
DESC -> height of country Code Number Input Height
Welcome Page customizations:
headerFontSize(double)
DESC -> welcome page header font size
imageDescriptionFontSize(double)
DESC -> welcome page image description font size
descriptionFontSize(double)
DESC -> welcome page description font size
imageHeight(double)
DESC -> welcome page image height
imageWidth(double)
DESC -> welcome page image width
buttonFontSize(double)
DESC -> welcome page button font size
buttonWidth(double)
DESC -> welcome page buttonWidth
buttonIconSize(double)
DESC -> welcome page buttonIconSize
ThankYou Page customizations:
headerFontSize(double)
DESC -> thank you page header font size
imageDescriptionFontSize(double)
DESC -> thank you page image description font size
descriptionFontSize(double)
DESC -> thank you page description font size
imageHeight(double)
DESC -> thank you page image height
imageWidth(double)
DESC -> thank you page image width
buttonFontSize(double)
DESC -> thank you page button font size
buttonWidth(double)
DESC -> thank you page buttonWidth
buttonIconSize(double)
DESC -> thank you page buttonIconSize
visibilityTime(int)
DESC -> how long the thank you page should be visible
Event listeners:
Listener name | Description |
---|---|
onError | callback function will get fired when there’s an error. Example: Wrong survey type, wrong SDK token, wrong domain name, error while fetching survey data |
onNext | callback function will get fired when user answers current question and moves to the next question |
onSubmit | callback function will get fired after user completes the survey |
Using SurveySparrow Flutter SDK Helper functions for collecting feedback from a custom Survey UI:
Responses can be collected from a custom survey ui using the createAnswerPayloadCustomSurvey and submitCustomSurvey functions
Collecting The Response
Example:
// pass the same surveyObj array to all the createAnswerPayloadCustomSurvey function calls , all the answers should be collected as a single array of map for submission
var surveyObj = [];
// rating question
var ratingObj = CustomRating(data:4, skipped: false, timeTaken: 1, key: 1245);
createAnswerPayloadOtherSurvey(ratingObj, surveyObj);
// text question
var textObj = CustomTextInput(skipped: false, data: "some input", timeTaken: 1, key: 1234);
createAnswerPayloadOtherSurvey(textObj, surveyObj);
// multiple choice questions
var multipleChoiceObj = CustomMultiChoice(data: [1,2,3], skipped: false, timeTaken: 3, key: 1289);
createAnswerPayloadOtherSurvey(multipleChoiceObj, surveyObj);
// yesno
var yesOrNoObj = CustomYesNo(key: 123,skipped: false,data: true,timeTaken:4);
createAnswerPayloadOtherSurvey(yesOrNoObj, surveyObj);
//email
var emailObj = CustomEmailInput(skipped: false, data: "abc@gmail.com", timeTaken: 2, key: 2908);
createAnswerPayloadOtherSurvey(emailObj, surveyObj);
// opnionScale
var opnionScaleObj = CustomOpinionScale(key: 1908,skipped: false,data: 2,timeTaken: 3);
createAnswerPayloadOtherSurvey(opnionScaleObj, surveyObj);
//phone number
var phoneNumberObj = CustomPhoneNumber(skipped: true, data: "+91 8976546789", timeTaken: 2, key: 1289);
createAnswerPayloadOtherSurvey(phoneNumberObj, surveyObj);
Submitting the response
Example:
token = “tt-3d4efc”
domain = “sample.surveysparrow.com”
submitCustomSurvey(domain,token,surveyObj);
Libraries
- components/common/cxEmailForm
- components/common/feedBackQuestionColumn
- components/common/header
- components/common/questionColumn
- components/common/skipAndNext
- components/loadingScreen
- components/questions/cesScore
- components/questions/csatFeedback
- components/questions/multichoice
- components/questions/npsFeedback
- components/questions/npsScore
- components/questions/opnion
- components/questions/phone
- components/questions/rating
- components/questions/text
- components/questions/yesorno
- components/thankyou
- components/welcome
- constants/survey
- eui
- helpers/answers
- helpers/cx
- helpers/question
- helpers/survey
- helpers/svg
- helpers/theme
- logics/displayLogic
- logics/jumpLogic
- logics/logicComparators
- logics/logics
- logics/mapLogicComparators
- logics/thankYou
- models/answer
- models/customSurveyTheme
- models/firstQuestionAnswer
- models/theme
- providers/answer_provider
- providers/survey_provider
- surveysparrow