How to Enable File Uploads in Framer Forms

Easily connect external storage—such as Cloudinary, Google Drive, Supabase, or Cloudflare R2—and add a file upload feature to your Framer forms.

Mastering Dynamic Pricing in Framer: Sliders, Steppers & Stripe/LemonSqueezy Integration
No headings found on page

Want to add file uploads to your Framer forms? This guide will show you exactly how to set it up.

The setup is simple. Add the File Upload Form component inside your form, then connect it to an external storage provider. You can also customize the design to match your project.

*You will need the File Upload Form component to follow this guide.



Use Cases

  1. Quick Public Uploads

If you just need to collect public or low-risk files, start with a direct upload provider. This is the fastest way to receive images, PDFs, event materials, portfolio files, or simple contact form attachments.

For this kind of workflow, Cloudinary, Google Drive, or Supabase Direct can be enough.

  1. Secure Production Uploads

If users are uploading sensitive files, private documents, customer-specific assets, legal files, or anything that should not be publicly accessible, do not upload directly from the browser using secret credentials.

For production-grade uploads, use Cloudflare R2 Worker, a Supabase Edge Function, or a Custom Endpoint. This gives you a server-side layer where you can validate the file, check the user, protect secret keys, and control what happens after upload.



Which Storage Should You Choose?

Storage

Best for

Setup

Security

Cloudinary

Images, PDFs, media files, and fast public uploads

Easy

Medium

Google Drive

Saving uploaded files into your own Drive folder

Easy

Medium

Supabase Direct

Public or low-risk uploads into Supabase Storage

Moderate

Low to medium

Cloudflare R2 Worker

Scalable storage with server-side validation

Moderate

High

Custom Endpoint

Sensitive files, private flows, authentication, and custom logic

Advanced

High


Option 1. Cloudinary (Recommended)

Cloudinary is the easiest direct upload option. It is a good fit for images, PDFs, media files, and lightweight public upload flows.


Step 1. Prepare Cloudinary

Create a Cloudinary account, find your Cloud Name, and create an unsigned upload preset. If you need to upload PDFs or ZIP files, make sure PDF and ZIP delivery is allowed in your Cloudinary security settings.


Step 2. Fill in the Component Settings

In the component settings, fill in

  • Cloud Name

Enter your Cloudinary cloud name.

  • Upload Preset

Enter Your unsigned upload preset.

  • Folder

Optional. Use something like framer-uploads if you want to keep files organized.



Option 2. Google Drive

Google Drive mode uses Google Apps Script as a bridge between your Framer site and your Drive folder.

The flow is: Framer component → hidden iframe form → Google Apps Script Web App → Google Drive folder → file URL returned to the component.


Step 1. Create a Google Drive Folder

Create the folder where uploaded files should be saved. The folder itself does not need to be public. The Apps Script runs using the Google account that deployed it, and each uploaded file can be shared individually with anyone who has the link.


Step 2. Create the Apps Script

Open Google Apps Script, create a new project, and paste in the code from googleAppsScriptDriveUpload.gs. Then update the folder value at the top.

You can use either the full folder URL or only the folder ID.


Step 3. Deploy as a Web App

In Apps Script, create a new Web App deployment. Set Execute as to Me, and set Who has access to Anyone.

After deployment, copy the Web App URL that ends with /exec. Do not use the /dev URL or the Apps Script editor URL.


Step 4. Fill in the Component Settings

  • Upload URL

Paste your Google Apps Script Web App /exec URL.

  • Result Path

Use url.


Apps Script is convenient, but it is not ideal for very large files or high-frequency production uploads. For sensitive files, use a custom endpoint instead.



Option 3. Supabase Direct

Supabase Direct uploads straight from the browser into Supabase Storage. It is useful for public or low-risk files, but you need to understand your bucket and RLS policies.


Step 1. Prepare Supabase

Create a Supabase project, create a Storage bucket, and find your legacy anon public JWT key. For quick testing, a public bucket is the simplest starting point.


Step 2. Fill in the Component Settings

  • Supabase URL

Enter your project URL, such as https://your-project.supabase.co.

  • Supabase Key

Enter the anon key.

  • Bucket

Enter the bucket name

  • Folder Path(Optional)

Enter the folder path inside the bucket, such as uploads or form-submissions.


Step 3. Add Storage Policies

Add an insert policy for uploads:





If the files need public URLs, also add a read policy:





Replace uploads with your actual bucket name.

Avoid Supabase Direct for ID documents, contracts, sensitive resumes, customer-specific private files, and medical, legal, or payment-related documents. For those cases, use an Edge Function or Custom Endpoint.



Option 4. Cloudflare R2 Worker

Cloudflare R2 is a stronger option when uploads need a server-side layer. Instead of exposing storage credentials in the browser, the component sends the file to a Worker, and the Worker stores it in R2.

The flow is: Framer component → Cloudflare Worker → R2 bucket → public file URL returned.


Step 1. Prepare Cloudflare

Create an R2 bucket, create a Worker, add an R2 bucket binding to the Worker, and set up an R2 public URL or custom domain.


Step 2. Configure the Component

  • Storage

Select Cloudflare R2 Worker.

  • Upload URL

Paste your Worker URL.


Step 3. Return the File URL

Your Worker should return JSON like this:





For production, add max file size checks, allowed file type checks, allowed origin validation, CAPTCHA or token verification, and rate limiting.


Option 5. Custom Endpoint

Custom Endpoint is the most flexible upload mode. You can use your own server, a Vercel route, a Netlify function, a Supabase Edge Function, a Cloudflare Worker, or any endpoint that accepts a file and returns JSON.


Endpoint Contract

The component sends a POST request with multipart/form-data. By default, the file field is file.

Your endpoint should return the final file URL:





Use This Mode When

Use a custom endpoint when you need login validation, private files, secret keys, file type validation, file size validation, virus scanning, rate limiting, database writes, email notifications, or CRM integrations.



Security Checklist

Never put private credentials inside browser-side component settings.

  • Do not expose a Supabase service role key.

  • Do not expose a Supabase secret key.

  • Do not expose a Google private key.

  • Do not expose a Cloudflare API token.

  • Do not expose an AWS secret key.

Browser-side values can include a Cloudinary unsigned upload preset, a Supabase anon public JWT with correct RLS policies, a public upload endpoint URL, or a Google Apps Script Web App /exec URL.



Troubleshooting

  • Cloudinary PDF link does not open

Allow PDF and ZIP delivery in Cloudinary, use Cloudinary Type: Raw, and upload a fresh test file.

  • Supabase InvalidKey

Check that your key starts with eyJ, belongs to the same project as your Supabase URL, and that the Bucket field contains only the bucket name.

  • Supabase RLS error

Add an insert policy on storage.objects. If you need public file URLs, also add a select policy.

  • Google Drive upload times out

Make sure the Web App URL ends with /exec, access is set to Anyone, Execute as is set to Me, and you deployed a new version after code changes.

  • R2 upload succeeds but the link returns 401

The object may be stored, but the returned URL is not publicly accessible. Set up R2 public access or a custom domain, then update the Worker PUBLIC_BASE_URL.

nimbus clouds and blue calm sky

Discover 50+,
Weekly Updated Framer Resources