top of page

Uploading Images to Bubble via API from FlutterFlow

A step-by-step guide to handling image uploads through Bubble backend workflows using custom functions in FlutterFlow.


If you’re building in FlutterFlow and need to upload images directly to the Bubble database (without relying on third-party hosting services like AWS or Cloudinary), this post is for you.


I’ve been working across FlutterFlow and Bubble to build a mobile app for  Travel Keeper and one area that got a little tricky to build was the process for uploading and saving images for things like profile pictures to the Bubble database.


I’ll cover how I used Bubble backend workflows, APIs, and structured parameters to enable the uploading of images via API.


Step 1: Create Your Bubble Workflow


In my app, new users go through a multi-step sign-up flow:


  • Step 1 signs them up with email/password (via a backend workflow).

  • Step 2 updates their account with details like First Name, Last Name, a profile picture, a slug, and triggers an onboarding email series.


In Bubble, I created a backend workflow like this:


  • Workflow Name: sign-up-user-step2

  • Trigger Type: POST

  • Parameters:

    • userID: type text

    • firstname: type text

    • lastname: type text

    • profilepic: type file

signup step 2 workflow
Sign up Step 2 Backend Workflow
make changes to user step
Assigning the "profilepic" to "avatar"


The profilepic parameter is where the magic happens—it’s of type file, which accepts a JSON object that includes a base64-encoded image.


According to Bubble’s documentation, a file upload must follow this structure:

{ 
  "filename": "String", 
  "contents": "Base64-encoded binary data", 
  "private": false, 
  "attach_to": "String" 
}

In the workflow, I use “make changes to the user” and update the avatar field (my profile picture field) using this profilepic parameter, along with other fields on the record.


Step 2: Set Up Custom Functions in FlutterFlow


To prepare the image and wrap it in the correct JSON format, I built two custom functions in FlutterFlow:


Function 1: Convert Image to Base64


Bubble requires base64 encoding for image uploads. Base64 conversion for an image file transforms the file's binary data into a text-based format, making it easier to embed images directly into HTML or JSON without needing a separate file upload.


In FlutterFlow, I created a simple custom function that takes an image file and converts it to base64 format.


Here’s the code I used:

String? convertImageToBase64(FFUploadedFile? image) { 

	if (image == null) return null; 

	final bytes = image.bytes; 

	if (bytes == null) return null; 

	final base64Image = base64Encode(bytes); 

	return base64Image; 
}

custom function for image conversion
Custom Function: Convert Image to Base64

Function 2: Create JSON for Upload


Next, I needed to package my base64 image into a JSON format with the other fields required by Bubble. 


This is done with another custom function in FF that takes the inputs (filename and the base64 image data) and returns a structured JSON output that can be passed to Bubble. 


Here’s the code I used:

dynamic createImageJSON(
 String? filename,
 String? base64image,
) {
 /// MODIFY CODE ONLY BELOW THIS LINE

 // create a JSON object with this format:  {"filename":"filename argument", "contents": "base64image"}
 return {
   "filename": filename ?? "",
   "contents": base64image ?? "",
 };

 /// MODIFY CODE ONLY ABOVE THIS LINE
}

custom function for json
Custom Function to create the JSON

Step 3: Connect Everything in FlutterFlow


Now that the image is converted and formatted, here’s how I integrated it into the app flow:


1. Create the API Call


In the FlutterFlow API tab:


  • I created a new API call for the sign-up-user-step2 workflow in Bubble.

  • I added all required parameters (userID, first/last name, and profilepic), and set profilepic’s type to JSON.

  • I then created the Body structure for the JSON in the Body tab like this:

api call variables
API call variables
json body format
JSON Body format

2. Use the Custom Functions in Your UI


There are a few ways to handle the image conversion to base64 in the UI, but in my example, I decided to create a Page State called ProfilePicBase64 and use that to save the base64 conversion string. 


In my sign-up flow page:


  • I created a Page State variable called ProfilePicBase64.

  • I used the "Store media for upload" action when a user selects to add a photo.

  • I then called the base64 custom function and saved the result to the Page State.

  • (I also resized the image to 1200x1200 px before conversion to manage file size.)


setting page state
Calling the base64 conversion custom function on Page State

3. Trigger the API Call


Once the image is uploaded and saved to the Page State in base64-encoded format, I triggered the API as part of my action flow for the button on the screen.


  • I used the createImageJSON custom function for the profilepic field to wrap the base64 image and a filename into an accepted structure.

  • The filename is created using a combination of the user’s ID and "ProfilePic".

api call setup
Setting up the API call with createJSON function for profilepic

function input definition
Adding the inputs to the createJSON function

Result


After the API call runs successfully, the image is saved to Bubble’s File Manager and linked to the user’s account. You can check that the file is saved properly in Bubble by going to the Data section and clicking on File Manager.


Final Thoughts


This setup is efficient, reliable, and keeps your assets all in one place—perfect if you're building in FlutterFlow but using Bubble as your backend.


If you’re doing something similar or have questions, feel free to reach out. Happy building!




bottom of page