Create a terms of service screen using a SingleChildScrollView with a RichText widget for formatted legal content. Add an I Agree checkbox bound to Page State that enables a Continue button via Conditional property. On acceptance, update the user's Firestore document with tosAccepted and tosAcceptedAt fields. Gate app access by checking this field on home page load and redirecting unaccepted users back to the TOS page.
Building a Terms of Service Screen in FlutterFlow
App stores and regulations often require users to accept terms of service before using your app. This tutorial builds a professional TOS screen with scrollable formatted text, a checkbox agreement, and Firestore tracking. You will also learn how to prevent users from accessing the app without accepting.
Prerequisites
- A FlutterFlow project with Firebase or Supabase authentication configured
- A users collection in Firestore with a document per user
- Your terms of service text ready (or placeholder text for testing)
- Basic understanding of Page State and Action Flow in FlutterFlow
Step-by-step guide
Create the TOS page with a SingleChildScrollView layout
Create the TOS page with a SingleChildScrollView layout
Add a new page called TermsOfServicePage. Set the page scaffold body to a Column. Inside the Column, add a SingleChildScrollView as the first child (set it to Expanded so it fills available space). Inside the scroll view, add a Padding widget (16px all sides), then a RichText widget. The RichText lets you format headings in bold, body text in regular weight, and numbered lists — all within one text block. Below the SingleChildScrollView (still inside the outer Column), add a Divider, then a Row for the checkbox and button.
Expected result: A page layout with scrollable text area on top and a fixed checkbox/button row pinned at the bottom.
Format the legal text using RichText with styled spans
Format the legal text using RichText with styled spans
Select the RichText widget. In the Properties Panel, click Edit Rich Text. Add text spans for each section: set section headings like '1. Acceptance of Terms' to Bold weight and a larger font size (18px). Set body paragraphs to Regular weight at your Body Medium size (14px). Add line breaks between sections. For numbered items, type the numbers manually as part of the text. Use your Theme typography styles for consistent formatting.
Expected result: The TOS text displays with proper heading and body formatting inside the scrollable area.
Add the I Agree checkbox and conditionally enabled Continue button
Add the I Agree checkbox and conditionally enabled Continue button
Add a Page State variable called hasAgreed (Boolean, default false). Below the Divider, add a Row. First child: a Checkbox widget bound to hasAgreed via On Changed → Update Page State. Next to it: a Text widget saying 'I have read and agree to the Terms of Service'. Second row item: a Button with text 'Continue'. On the Button, set the Conditional property so it is enabled only when hasAgreed is true. When disabled, the button appears greyed out and is not tappable.
Expected result: The Continue button is greyed out until the user checks the I Agree checkbox.
Save TOS acceptance to the user's Firestore document
Save TOS acceptance to the user's Firestore document
On the Continue button's On Tap action, add an Update Document action targeting the current user's document in the users collection. Set two fields: tosAccepted to true and tosAcceptedAt to the current timestamp (use Global Properties → Current Time). After the update succeeds, add a Navigate action with Replace Route to your home page. Using Replace Route prevents the user from pressing Back and returning to the TOS screen.
Expected result: Tapping Continue saves acceptance to Firestore and navigates to the home page without back-navigation to TOS.
Gate app access by checking TOS acceptance on home page load
Gate app access by checking TOS acceptance on home page load
On your home page, open the On Page Load action flow. Add a Conditional Action: check if currentUser.tosAccepted equals true. If false (user has not accepted), add a Navigate action to TermsOfServicePage with Replace Route. If true, continue loading the page normally. This ensures users who skip the TOS (e.g., via deep link) are always redirected to accept before using the app.
Expected result: Users who have not accepted TOS are redirected to the TOS page on every home page load attempt.
Complete working example
1PAGE: TermsOfServicePage23PAGE STATE:4 hasAgreed: Boolean = false56WIDGET TREE:7 Column8 ├── Expanded9 │ └── SingleChildScrollView10 │ └── Padding (16px all)11 │ └── RichText12 │ ├── Span: "Terms of Service" (Bold, 24px)13 │ ├── Span: "\nLast updated: March 2026\n\n" (Regular, 12px, grey)14 │ ├── Span: "1. Acceptance of Terms\n" (Bold, 18px)15 │ ├── Span: "By accessing this app...\n\n" (Regular, 14px)16 │ ├── Span: "2. User Obligations\n" (Bold, 18px)17 │ └── Span: "You agree to...\n\n" (Regular, 14px)18 ├── Divider19 └── Padding (16px horizontal, 12px vertical)20 └── Column21 ├── Row22 │ ├── Checkbox (bound to hasAgreed)23 │ └── Text: "I have read and agree to the Terms"24 └── Button: "Continue"25 ├── Enabled: hasAgreed == true26 └── On Tap:27 1. Update Document: users/{uid}28 → tosAccepted = true29 → tosAcceptedAt = Current Time30 2. Navigate (Replace Route): HomePage3132HOME PAGE — ON PAGE LOAD:33 1. Conditional: currentUser.tosAccepted != true34 → Navigate (Replace Route): TermsOfServicePageCommon mistakes when creating a Custom Terms of Service Screen for Your FlutterFlow App
Why it's a problem: Using a plain Text widget for long legal content
How to avoid: Use a RichText widget inside a SingleChildScrollView. RichText supports mixed formatting within one text block, and SingleChildScrollView enables scrolling.
Why it's a problem: Using Navigate To instead of Replace Route after TOS acceptance
How to avoid: Use Navigate with Replace Route so the TOS page is removed from the stack. The home page becomes the new root.
Why it's a problem: Hardcoding TOS text directly in the widget tree
How to avoid: Store TOS content in a Firestore document and fetch it via Backend Query. Update the text in Firestore without touching the app.
Best practices
- Store TOS content in Firestore so you can update it without republishing the app
- Record the acceptance timestamp alongside the boolean for legal audit trails
- Use Replace Route navigation after acceptance to prevent back-button return to TOS
- Check TOS acceptance on the home page On Page Load to catch all entry points
- Include a version field on the TOS document and re-prompt acceptance when the version changes
- Add a link to the TOS page in your app's settings screen for users to review later
- Keep the checkbox and button visible at the bottom without scrolling — only the text should scroll
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
I need to build a terms of service screen in FlutterFlow with formatted scrollable text, an I Agree checkbox that enables a Continue button, Firestore acceptance tracking with timestamp, and a home page check that redirects unaccepted users. Provide the full widget tree and action flow.
Create a new page called TermsOfServicePage with a Column layout. Add a scrollable text area at the top taking most of the screen, a divider, then a row with a checkbox and a button at the bottom.
Frequently asked questions
Do I legally need a terms of service screen?
Both Apple App Store and Google Play Store require apps to have accessible terms of service. While the legal specifics depend on your jurisdiction, having a TOS screen is a best practice for any published app.
How do I update the TOS without requiring a new app version?
Store the TOS text in a Firestore document. Update the text there, and the app fetches the new version automatically. Add a version field to re-prompt acceptance when major changes occur.
Can I make the checkbox disabled until the user scrolls to the bottom?
Yes, but it requires a Custom Widget with a ScrollController that detects when the user reaches the bottom and then enables the checkbox via a callback. The built-in ScrollView does not have this feature natively.
Should I show TOS before or after account creation?
Best practice is to show TOS during sign-up before creating the account. This way you have consent before storing any user data. Alternatively, show it immediately after first login.
How do I handle TOS acceptance for existing users after an update?
Add a tosVersion field to the user document. When you update TOS, increment the version in Firestore. On home page load, compare the user's accepted version to the current version and redirect to TOS if outdated.
Can RapidDev help with legal compliance in my app?
RapidDev can build the technical infrastructure for TOS, privacy policy, and consent management in your FlutterFlow app. For the legal text itself, consult a lawyer.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation