Forms June 28, 2026 5 min read Updated July 29, 2026

Handling file uploads in Webflow beyond the built-in size limit

Webflow's upload field is fine for a CV and unusable for a video. Three routes past the limit, and the client-side compression that avoids the problem entirely.

On this page

Where the wall is

Webflow's file upload field has a size cap — 10MB on standard plans. Under it, everything works and files attach to the submission. Over it, the submission is rejected.

That's fine for a CV or a brief. It's not fine for design files, video, or photos straight off a modern phone, which routinely exceed it. And the failure lands on the visitor, who has already filled in the form, at the moment they press submit.

Before engineering around it, do the cheap thing: state the limit next to the field, before they choose a file. A large share of "the form is broken" reports are someone attaching a 40MB video with no indication that was ever going to fail.

<label for="brief">Attach your brief</label>
<input type="file" id="brief" name="brief" accept=".pdf,.doc,.docx">
<p class="hint">PDF or Word, up to 10MB.</p>

And validate client-side so they find out immediately rather than after filling everything else in:

const input = document.querySelector('#brief');
const MAX = 10 * 1024 * 1024;

input.addEventListener('change', () => {
  const file = input.files[0];
  if (!file) return;

  if (file.size > MAX) {
    const mb = (file.size / 1024 / 1024).toFixed(1);
    alert(`That file is ${mb}MB. The maximum is 10MB — please compress it or send a link.`);
    input.value = '';
  }
});

Telling someone the actual size of their file is worth the extra line. "Too big" invites a resubmission of the same file; "that file is 34.2MB, maximum is 10MB" does not.

Route 1: compress in the browser

For images — which is most of what exceeds the limit — you can resize before upload and often stay well under the cap with no perceptible quality loss. A 12MB phone photo becomes 800KB at a resolution nobody will complain about.

async function shrink(file, maxWidth = 2000, quality = 0.82) {
  if (!file.type.startsWith('image/')) return file;

  const bitmap = await createImageBitmap(file);
  if (bitmap.width <= maxWidth) return file;

  const scale = maxWidth / bitmap.width;
  const canvas = document.createElement('canvas');
  canvas.width = maxWidth;
  canvas.height = Math.round(bitmap.height * scale);
  canvas.getContext('2d').drawImage(bitmap, 0, 0, canvas.width, canvas.height);

  const blob = await new Promise(res => canvas.toBlob(res, 'image/jpeg', quality));
  if (!blob || blob.size >= file.size) return file;   // never make it worse

  return new File([blob], file.name.replace(/\.\w+$/, '.jpg'), { type: 'image/jpeg' });
}

To use it, replace the file in the input via a DataTransfer:

input.addEventListener('change', async () => {
  const file = input.files[0];
  if (!file) return;

  const smaller = await shrink(file);
  if (smaller !== file) {
    const dt = new DataTransfer();
    dt.items.add(smaller);
    input.files = dt.files;
  }
});

Two caveats worth being straight about. This strips EXIF, including orientation — most browsers now bake rotation into createImageBitmap, but test with a portrait photo from an actual phone before trusting it. And it's lossy: never apply it to documents, and don't apply it where the original file is the deliverable, such as a print-ready asset.

Route 2: upload elsewhere, submit the URL

The general solution. The file goes directly to storage built for files; the form carries a link.

Flow: visitor picks a file → JavaScript requests a short-lived upload URL from your backend → browser uploads straight to storage → the resulting URL populates a hidden field → the form submits normally.

async function uploadDirect(file) {
  // Your endpoint returns a pre-signed URL. The storage credentials
  // stay on the server — never put them in client-side code.
  const res = await fetch('/api/upload-url', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ name: file.name, type: file.type, size: file.size }),
  });

  const { uploadUrl, publicUrl } = await res.json();

  await fetch(uploadUrl, {
    method: 'PUT',
    headers: { 'Content-Type': file.type },
    body: file,
  });

  return publicUrl;
}

The hard requirement: the storage credentials must never reach the browser. Pre-signed URLs exist precisely so the browser can upload without holding a key. Any tutorial putting an S3 secret in front-end JavaScript is describing how to have your bucket emptied.

You also need a size ceiling and a type allow-list enforced on the server when issuing the URL. Client-side checks are a UX nicety; anyone can skip them.

This route needs a backend, which for a Webflow site means a serverless function or a service like Uploadcare or Filestack that packages the whole flow.

Route 3: don't take the file at all

Frequently the best answer, and the one nobody suggests because it feels like a cop-out.

Ask for a link. "Share a Google Drive, Dropbox or WeTransfer link to your files." One text field, no upload infrastructure, no size limit, and the person sending 400MB of design files already has those files in cloud storage.

It's a worse experience for someone with a single small PDF, so offer both: a small upload field for documents, and a link field for anything large.

For recruitment, this is often already how it works — candidates have their CV in Drive.

Security, briefly but seriously

Any route that accepts files needs these, and the first two are not optional:

Validate type on the server, by content. File extensions are a claim, not a fact. accept=".pdf" on the input is a hint to the file picker and nothing more.

Never serve uploads from your main domain as executable content. Serve from storage, or from a subdomain that can't run scripts.

Cap size server-side. Client checks are trivially bypassed.

Scan if the files reach anything sensitive. For a marketing site collecting briefs, a size and type gate is usually proportionate. For anything touching internal systems, scan.

Choosing

Situation Route
Documents under 10MB Native field, state the limit
Photos from phones Client-side compression
Large design files, video Ask for a link
Genuinely needs direct upload at scale Pre-signed URLs via a backend

Most sites should be on the first three rows. Route 2 is real engineering with real security obligations, and it's worth it only when the upload is central to what the form does — a job application portal, a print ordering flow — rather than a nice-to-have on a contact page.

Share

Our Products

We don’t just build apps; we create solutions that transform how you use Webflow. Whether you’re looking to streamline workflows, add advanced functionality, or scale your business, we’ve got you covered.

All apps