Guide 10 · Developer docs

Forms and data capture

Building forms with the Forms module: how a form is put together and placed on a page, validating and branching, presenting it, where submissions are stored, and what happens after one arrives, from jobs and records to CRMs and payments.

L1–L2
Unit 05 · Storing submissions

File uploads

Where a file uploaded with a form is stored, what the submission records about it, who can open it afterwards, the size and type limits, and the steps that keep uploads under control.

Who this is for. The site builder adding a File field to a form, and whoever answers for the client's data. Afterwards you know where an upload goes, how to accept files in each submission model, what the platform does and does not limit, and how to keep uploads from spreading.

A File field lets a visitor send a document or an image with a form: a CV, a photo of a damaged product, a signed agreement. It is also the part of a form most likely to cause a data disclosure, because of where the file goes and how long it stays there.

Where an uploaded file goes

An uploaded file is not kept inside the submission. It is saved into the site's Files manager, like a file an editor uploads, in a folder per submission:

user-files/form-submissions/<form name>/<submission token>/<the visitor's file name>

The answer stored on the submission is a list with one entry per file, pointing at it:

JSON
"cv": [
  { "type": "file", "id": 4182, "name": "cv.pdf", "link": "/files/user-files/form-submissions/Careers/3f9c…e1/cv.pdf" }
]

type is image when the file is a picture (it is then an image record, resizable like any other) and file otherwise. Three consequences follow from where it is kept:

  • Anyone who can open the Files manager can open every upload. That is usually a wider group than the people meant to read submissions: every editor who manages images.
  • Deleting a submission does not delete its files. The submission's answers go; the folder and its files stay in the Files manager, at their addresses, until someone deletes them there.
  • A file is stored when its own step passes. Files are saved after the step they are on has been validated, whether or not the submission is ever completed. On a public form without Require completed captcha, that includes a submission that never solves the captcha, as long as the file is on another step. Tick that setting on every public form with a file field.

Uploads in each submission model

  • Page per step posts the step as multipart/form-data, which the layout declares when the step has a file field (the minimal layout). The file keeps its name.
  • The JS model, and any client that posts JSON, sends each file as a data URL inside the body. It is stored as uploaded_file with an extension taken from its type, not under the visitor's file name (Submitting a form through the API).
  • A required File field is satisfied only by a file part of a multipart request. Send files as file parts of a multipart request. On a JS-model form, leave the File field optional and enforce it in the browser, or send that form as multipart.

Who can open it afterwards

Two groups. Admin users who can open the Files manager, as above. And anyone who has the file's address: every file in the Files manager is delivered from its /files/… address like any other file on the site, without signing in, and the platform offers no setting to restrict one folder. What keeps an upload private is that its address is hard to guess, because the folder name is the submission's 60-character token.

That holds only as long as the address stays private, and addresses travel: a staff notification that includes it, a CRM record it is pushed into, a forwarded email, a browser history on a shared computer. Treat the address of an upload the way you would treat the file itself, and keep uploads out of the places such addresses spread to (below).

Size and type limits

LimitWhere it is setWhat the visitor sees when it is exceeded
File typeNowhere. The field prints no accept, and the server checks no typeNothing: any file is accepted
Size per fileUp to 500 MB per file, set by the server, not the formNo message on the field when a file is larger. Test the largest file you expect on the live environment
Number of filesAllow multiple file uploads on the element allows several; there is no limit on the number

On the JS model every step is sent in one request, and base64 makes each file about a third larger on the way, so a large upload is better sent from a page-per-step form, as an ordinary file part.

Since the platform checks no type, and a file can be up to 500 MB, check both in the browser, where the visitor can still fix the choice. It does not stop a determined sender, but it stops every honest mistake, which is most of them. Add accept and a size check to every file field in the site's forms bundle:

JavaScript
// src/js/forms/files.js
const ACCEPT = '.pdf,.doc,.docx,.jpg,.jpeg,.png';
const MAX_BYTES = 8 * 1024 * 1024;

export function guardFileFields(root = document) {
  root.querySelectorAll('input[type="file"]').forEach((field) => {
    field.accept = field.accept || ACCEPT;
    field.addEventListener('change', () => {
      const files = Array.from(field.files);
      const allowed = ACCEPT.split(',');
      const tooBig = files.find((file) => file.size > MAX_BYTES);
      const wrongType = files.find((file) => !allowed.some((ext) => file.name.toLowerCase().endsWith(ext)));
      field.setCustomValidity(
        tooBig ? `${tooBig.name} is larger than 8 MB.` :
        wrongType ? `${wrongType.name} is not a PDF, Word document or image.` : ''
      );
      field.reportValidity();
    });
  });
}

Say the rule in the field's label as well ("PDF, Word or image, up to 8 MB"), so the visitor knows it before choosing. And because a browser never puts a file back into a file field, the visitor has to choose it again after any error on that step: say so in the error summary.

Keeping uploads under control

The controls are in how the site is built and run. In order of effect:

  1. Do not collect files you do not need. If the business needs documents from known people (a signed contract, an identity document), collect them somewhere that authenticates the reader: a document-signing service, a client portal, or a secure email address published on the form.
  2. Never put an upload's address in an email or a chat message. Link the person to the submission in the admin instead, where reading it requires signing in. In a notification job, list the file's name, not its link.
  3. Move files out, then delete them. When uploads belong in another system (a CRM, an HR platform, a ticketing tool), have the job on the form's Completed event send each file there, then delete the file record by the id in the answer with a Delete record action, after the transfer has succeeded (Record actions). The submission keeps the file's name, and its address stops working, which is the point.
  4. Restrict the Files manager. Give access only to the editors who need it, and remember that it includes the submissions folder.
  5. Delete on a schedule. Agree how long uploads are kept (Retention and privacy) and delete the per-submission folders when they are due, along with their submissions.

Before launch, test it yourself: submit a test file on the live site, take its link from the submission, and open it in a private browser window. If the file opens, so will anyone's who has that address, and the steps above are what keep the address from reaching them.

Go deeper

Was this page helpful?

Your answer goes to the docs team.