Automating user onboarding: Flutterflow + Supabase + Loops email integration
See how three powerful tools work together to create professional user onboarding flows

Introduction
I frequently build mobile and web applications using No Code and Low Code tools. Through my journey, I've documented various integration patterns in my No Code & Low Code blog series. Recently, I've been deep into FlutterFlow development with Supabase as the backend, and one challenge kept coming up: automating the user onboarding email flow with temporary passwords.
Last week, I was building an application where administrators needed to create user accounts on behalf of customers. The flow seemed straightforward—admin creates account, user receives email with credentials, user confirms email and logs in. However, connecting FlutterFlow's signup action with Supabase's authentication system and Loops' email service turned out to be more nuanced than expected.
The breakthrough came when I realized that Supabase's email confirmation system could be configured to use Loops as the SMTP provider, and user metadata could be passed through to email templates. This discovery transformed a potentially complex multi-step process into an elegant, automated flow.
Having refined this integration pattern, I decided to write this tutorial-style blog post to document the exact steps involved, hoping it might help someone (including future me 😉) who needs to implement a similar onboarding system.
Let's get going 🛹
A Bit of Context
In the application I'm building, administrators create accounts for customers who will then use the platform. The business requirements were clear:
Admin creates the account with the user's email and basic information
System generates a random temporary password
User receives an email with their credentials and a confirmation link
User clicks the confirmation link to verify their email address
User logs in with the temporary password
System forces password change on first login for security
From a technical perspective, this involves orchestrating three different systems:
FlutterFlow: The frontend where admins create accounts
Supabase: The backend handling authentication and database
Loops: The email service provider for transactional emails
The key challenge was passing the randomly generated password from FlutterFlow through Supabase to Loops, while maintaining proper authentication flows and security practices.
💡 Why this stack? FlutterFlow offers rapid mobile/web development, Supabase provides robust authentication with row level security, and Loops excels at beautiful transactional emails. Together, they create a powerful, scalable onboarding system.
What We're Building Today
We're going to build a complete user onboarding system that:
Generates random temporary passwords in FlutterFlow
Creates user accounts in Supabase Auth
Stores user profiles with metadata
Sends branded confirmation emails via Loops
Handles email verification and redirects
Forces password changes on first login
This real-world scenario covers the entire authentication flow from account creation to secure first login.
Prerequisites
Important: This tutorial assumes you already have working knowledge of FlutterFlow and Supabase. If you are brand new to either platform, I recommend getting familiar with the basics first before tackling this integration.
Before we begin, make sure you have:
FlutterFlow project set up with Supabase integration
Supabase project with authentication enabled
Loops account with SMTP credentials
Basic understanding of FlutterFlow custom actions
Familiarity with Supabase authentication concepts
Part 1: Setting Up Loops SMTP in Supabase
This is the foundation that makes everything work. We're going to configure Supabase to send all authentication emails through Loops.
Step 1: Get Your Loops SMTP Credentials
Log in to your Loops dashboard
Navigate to Settings → Supabase
Click on Connect Supabase in the SMTP section
Step 2: Connect Loops to Your Supabase Project
Once you're on the Loops Supabase integration screen, here's what happens:
Authorize Supabase access
Click to connect your Supabase account
Supabase will prompt you to select your organization
Click "Authorize" to grant Loops access
Configure the connection
Back in Loops, select your Supabase project from the dropdown
Choose an API key (this becomes your SMTP password)
Click "Set up SMTP"
Verify the setup
Loops automatically adds its SMTP credentials to your Supabase project
You'll see a success message: ✓ "SMTP has been set up in your Supabase project"
Behind the scenes, Loops configures these SMTP settings in your Supabase project:
Host:
smtp.loops.soPort:
587Username:
loopsPassword: One of your Loops API keys
You can verify these credentials anytime in Supabase by going to Authentication → Emails → SMTP Settings.
💡 Note: The API key you select becomes your SMTP password. You can find and manage your API keys in Loops under Settings → API.
Step 3: Configure Supabase SMTP Settings
Open your Supabase project dashboard
Go to Project Settings → Authentication → SMTP Settings
Enable Custom SMTP
Fill in the Loops credentials:
Host: Your Loops SMTP host
Port number: 587
Sender email: The email address you want emails to come from
Sender name: Your application name (e.g., "Your App Team")
Username: Loops SMTP username
Password: Loops SMTP password
Note: Sender email address and name can be overwritten in the Loops dashboard.

- Click Save
💡 Important: Test your SMTP connection by creating a test user. If emails aren't sending, double-check your Loops credentials and ensure your sender email is verified in Loops.
Part 2: Creating the Email Template in Loops
Now let's design the email that users will receive with their credentials.
Step 1: Create a New Transactional Email
In Loops, go to Transactional → Create transactional email
Name it something like "User Welcome & Email Confirmation"
Design your email with these elements:
Greeting
Welcome message
Temporary credentials section
Security note about password change
Confirmation button
Signature
Here's the structure I use:
Hello,
Thank you for joining [Your App Name]. To get started, please use these credentials to log in:
Email: {{customer_email}}
Password: {{generated_password}}
Before you can access your account, please verify your email address by clicking the button below.
[Confirm my account button]
Important: You'll need to create a new password when you log in for the first time.
Regards,
The [Your App Name] Team
Step 2: Define Data Variables
In your Loops template, you need to define three data variables:
customer_email - The user's email address
generated_password - The temporary password
confirmationURL - Supabase's confirmation link
These variables will be populated dynamically when Supabase triggers the email.
Step 3: Get Your Transactional ID
After saving your template, Loops will generate a transactional ID. This is a unique identifier you'll use in Supabase to reference this specific email template.
Copy this ID—you'll need it in the next section.

Part 3: Configuring Supabase Email Template
This is where we connect Supabase's authentication system to your Loops template.
Step 1: Access Email Templates
In Supabase dashboard, go to Project Settings → Authentication → Email
Click on Confirm signup template
Step 2: Configure the Template for Loops
Replace the default template with this JSON structure:
{
"transactionalId": "your_loops_transactional_id_here",
"email": "{{.Email}}",
"dataVariables": {
"confirmationURL": "{{.ConfirmationURL}}",
"customer_email": "{{.Email}}",
"generated_password": "{{.Data.password}}"
}
}
Let me break down what each part does:
transactionalId: Your Loops template ID (paste the one you copied earlier)
email: Supabase variable for the user's email address
dataVariables: Object containing all dynamic values for your Loops template
confirmationURL: Supabase's auto-generated confirmation link
customer_email: Passes the email to Loops
generated_password: This is the critical part—it accesses the password we'll pass via user metadata

💡 Key insight: Notice we're using {{.Data.password}} not {{.UserMetaData.password}}. This accesses the user metadata object correctly in Supabase's template system.
Part 4: Building the FlutterFlow Custom Action
Now we'll create the FlutterFlow action that creates users and passes the password through to the email.
Step 1: Generate Random Password
First, create a custom action or use FlutterFlow's action flow to generate a random password. You can use a formula or custom code like:
String generateRandomPassword(int length) {
const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
final random = Random.secure();
return List.generate(length, (index) => chars[random.nextInt(chars.length)]).join();
}
I kept it simple, just made use a of a formula

Step 2: Create the Custom Action for User Creation
Create a custom action called createCustomerAccountAction with these parameters:
Input Parameters:
email(String)password(String) - The generated random passwordname(String)phonenumber(String)category(String) - User type/categoryrole(String) - User role
Return Type: String (success/error message)
Step 3: Implement the Custom Action Code
Here's the complete code for the custom action:
Future<String> createCustomerAccountAction(
String email,
String password,
String name,
String phonenumber,
String category,
String role
) async {
try {
final response = await SupaFlow.client.auth.signUp(
email: email,
password: password,
data: {
'name': name,
'phone_number': phonenumber,
'category': category,
'role': role,
'password': password, // THIS IS CRITICAL - Pass password in metadata
},
);
if (response.user != null) {
return 'Customer added successfully';
} else {
return 'Customer account creation failed!';
}
} catch (e) {
return 'Error: ${e.toString()}';
}
}
The crucial part: Notice we're passing password inside the data object. This stores it in the user's metadata (auth.users.raw_user_meta_data), making it accessible to our email template via {{.Data.password}}.
💡 Security note: The password in metadata is just for sending via email. Supabase automatically hashes the actual password (the one outside the data object) and stores it securely in auth.users.encrypted_password. The metadata password is only used for the email and can be removed after the user changes their password.
Step 4: Add This Action to Your Admin Interface
In your FlutterFlow admin screen where you create users:
Add form fields for email, name, phone, category, role
Add a button "Create User"
On button click, call your custom action:
Generate random password first (If you’re using a simple formula, then you don’t need this)
Pass all parameters including the generated password
Show success/error message
Part 5: Setting Up the User Profile Table
When Supabase creates a user in auth.users, it only stores authentication-related data (email, password hash, metadata). For your application, you'll likely need additional user information like name, phone number, role, and status in a separate table that you can query and manage easily.
We'll create a user_profiles table in the public schema to store this data, then set up a database trigger that automatically creates a profile record whenever a new user signs up.
Why do we need a separate user_profiles table?
auth.usersis managed by Supabase and has limited columns - you can't add custom fieldsuser_profilesgives you full control to store application-specific dataIt enables better Row Level Security policies for your app
You can query and join user data with other tables easily
It keeps authentication separate from application logic
Step 1: Create the user_profiles Table
In Supabase SQL Editor, create your user profiles table:
CREATE TABLE public.user_profiles (
id uuid PRIMARY KEY REFERENCES auth.users(id) ON DELETE CASCADE,
name text,
phone_number text,
category text,
role text,
status text DEFAULT 'inactive',
created_at timestamp with time zone DEFAULT now(),
updated_at timestamp with time zone DEFAULT now()
);
-- Enable Row Level Security
ALTER TABLE public.user_profiles ENABLE ROW LEVEL SECURITY;
Step 2: Create the Trigger Function
Create a function that automatically creates a user profile when a user signs up:
CREATE OR REPLACE FUNCTION public.handle_new_user()
RETURNS trigger AS $$
BEGIN
INSERT INTO public.user_profiles (
id,
name,
phone_number,
category,
role,
status
)
VALUES (
NEW.id,
NEW.raw_user_meta_data->>'name',
NEW.raw_user_meta_data->>'phone_number',
NEW.raw_user_meta_data->>'category',
NEW.raw_user_meta_data->>'role',
'inactive'
);
RETURN NEW;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
Step 3: Create the Trigger
CREATE TRIGGER on_auth_user_created
AFTER INSERT ON auth.users
FOR EACH ROW
EXECUTE FUNCTION public.handle_new_user();
This trigger automatically fires whenever a new user is created in auth.users, pulling data from the metadata and creating a corresponding profile record.
Part 6: Configuring Email Confirmation Redirect
After users click "Confirm my account", they need to be redirected back to your application.
Step 1: Set Up Redirect URLs in Supabase
Go to Authentication → URL Configuration
Set your Site URL to your application's URL (e.g.,
https://yourapp.flutterflow.app)Add Redirect URLs - these are the allowed URLs Supabase can redirect to after confirmation
💡 For FlutterFlow: Your redirect URL will typically be your published app URL. F
Part 7: Implementing First Login Password Change
Now we need to ensure users change their password on first login.
Step 1: Check User Status on Login
In your FlutterFlow login flow, after successful authentication:
Query the
user_profilestable for the current userCheck the
statusfieldIf status is
'inactive', redirect to password change screenIf status is
'active', redirect to main dashboard
Step 2: Create Password Change Screen
Build a simple screen with:
Password input field (with validation)
Confirm password input field
"Update Password" button
On button click:
Validate passwords match
Call Supabase's
updateUserfunction to change passwordUpdate user status to
'active'inuser_profilestableNavigate to dashboard

Step 3: Update User Status
Create a custom action or backend query to update the status:
Future<void> updateUserStatusToActive(String userId) async {
await SupaFlow.client
.from('user_profiles')
.update({'status': 'active'})
.eq('id', userId);
}
Part 8: Testing the Complete Flow
Time to test everything end-to-end!
Test Checklist:
Admin creates user ✓
Fill out the form with test data
Generate random password
Submit
Verify user in Supabase ✓
Check
auth.userstable for new userCheck
user_profilestable for matching recordVerify status is
'inactive'
Check email delivery ✓
Email should arrive with correct credentials
Verify password is visible
Check confirmation button works
Click confirmation link ✓
User should be redirected to your app
Email confirmation status should update in Supabase
Test first login ✓
Use credentials from email
Should redirect to password change screen (not dashboard)
Change password ✓
Set new password
Verify status updates to
'active'Should redirect to dashboard
Test second login ✓
Login with new password
Should go directly to dashboard
Common Issues and Troubleshooting
Issue 1: "Error sending confirmation email"
Cause: Usually a problem with the Loops template configuration or SMTP settings.
Solutions:
Verify your Loops SMTP credentials in Supabase are correct
Check that your Loops transactional ID is accurate
Ensure all data variables in Loops match what you're sending from Supabase
Look at Supabase Auth logs for specific error messages
Issue 2: Password not showing in email
Cause: Password not being passed correctly through metadata.
Solutions:
Verify you're using
{{.Data.password}}not{{.UserMetaData.password}}in templateCheck that
passwordis included in thedataobject in your FlutterFlow actionTest by checking
auth.users.raw_user_meta_datain Supabase to see if password is there
Issue 3: User can't log in after confirmation
Cause: Email might not be properly confirmed in Supabase.
Solutions:
Check
auth.users.email_confirmed_atfield—should have a timestampVerify redirect URLs are set correctly in Supabase
Ensure the confirmation link format matches Supabase requirements
Issue 4: Missing comma in Supabase template
Cause: JSON syntax error in email template configuration.
Solution: Ensure every line except the last one in objects has a comma:
{
"transactionalId": "xxx",
"email": "{{.Email}}", // comma here
"dataVariables": {
"confirmationURL": "{{.ConfirmationURL}}", // comma here
"customer_email": "{{.Email}}", // comma here
"generated_password": "{{.Data.password}}" // no comma on last item
}
}
Security Considerations
While this pattern works well for controlled environments, here are some security best practices:
1. Password Transmission
The risk: Passwords are sent via email, which is inherently less secure than other methods.
Mitigation:
Passwords are temporary and must be changed on first login
Email communication is over TLS/SSL
API calls are over HTTPS
For high-security applications, consider using "set password" links instead
2. Metadata Storage
The risk: Password stored in user metadata is in plaintext.
Mitigation:
This is only temporary for email sending
The actual authentication password is properly hashed by Supabase
Consider removing the metadata password after first login or after a time period
3. Email Interception
The risk: If someone intercepts the email, they get temporary access.
Mitigation:
Force password change on first login
Consider adding two-factor authentication
Monitor for suspicious login attempts
Set short expiration times for confirmation links
Pro Tips from My Experience
1. Always Check Supabase Logs
When debugging email issues, Authentication → Logs is your best friend. It shows exactly why an email failed to send.
2. Use Descriptive Variable Names
Instead of temp_pass, use generated_password. Your future self will thank you when debugging.
3. Test with Real Email Addresses
Don't rely solely on test accounts. Send to your actual email to see the real user experience.
4. Version Your Email Templates
Keep track of changes to your Loops templates. Loops has built-in versioning—use it.
5. Handle Edge Cases
What happens if:
User clicks confirmation link multiple times?
User never confirms email?
Password generation fails?
Build error handling for these scenarios.
6. Monitor Email Deliverability
Check your Loops dashboard regularly for bounce rates and delivery issues. Email deliverability can degrade over time if not monitored.
Extending This Pattern
Once you have this basic flow working, you can extend it for other use cases:
Password Reset Emails
Use the same Loops + Supabase pattern for password reset emails with custom branding.
Welcome Sequences
After confirmation, trigger a series of onboarding emails through Loops.
Role-Based Onboarding
Send different email templates based on user role or category stored in metadata.
Multi-Tenant Systems
Customize email branding based on the organization the user belongs to.
Conclusion
Connecting FlutterFlow, Supabase, and Loops for automated user onboarding creates a professional, scalable system that handles the complete authentication flow. By passing user metadata through Supabase's authentication system to Loops templates, we can send beautifully branded emails with dynamic content like temporary passwords.
This pattern works for any scenario where administrators create user accounts on behalf of customers. From SaaS platforms to membership sites to internal business applications, this integration pattern provides a robust foundation for user onboarding.
The key insight is understanding how data flows through the system:
FlutterFlow generates and passes data to Supabase
Supabase creates the user and triggers email
Email flows through Loops SMTP with dynamic variables
User confirms and logs in
First login flow ensures security with password change
Once you master this pattern, you'll find yourself using it across multiple projects. It's one of those integrations that seems complex at first but becomes second nature once you understand how the pieces fit together.
I've implemented this pattern across several client projects involving member management systems, professional service platforms, and collaborative tools.
Need help building your next application? Whether you're developing member portals, SaaS platforms, or business management systems, I can help you architect and build complete solutions with FlutterFlow, Supabase, and the entire modern no-code stack.
Ciao until next time! 👋
P.S. I build internal tools & SaaS products for clients using tools like FlutterFlow, Supabase, WeWeb, Xano, n8n and more. Have an idea you want to bring to life or need help building software? Send me a message on LinkedIn or DM me on X.



