Compose the fields in your own tree.
Fillo controls are components you restyle or replace — not a rendered survey you re-skin with CSS.
app.acme.co/setup/feedbackSetup feedback
Compare Formbricks with Fillo when self-hosting is not the goal: your own components render the fields, uploads go to storage you connect, and there are no services to operate.
Formbricks gives you the whole survey platform to run. Fillo is for when you'd rather compose the form from your own components and operate nothing — Fillo keeps the schema, responses, and files behind them.
Fillo controls are components you restyle or replace — not a rendered survey you re-skin with CSS.
app.acme.co/setup/feedbackSetup feedback
Connect Drive, Box, or an S3-compatible bucket once — uploads go browser-direct with no IAM, bucket policy, or CORS rules to write.
The same visibility rule renders the field in your app and gates what Fillo's server accepts.
Answers, files, versions, and delivery state live in a workspace you don't have to operate.
Formbricks is an open-source survey platform. Use its cloud, or run the whole thing yourself with Docker: responses stay on infrastructure you control, and the source is there to read and patch. Surveys go out as links, or as in-app surveys delivered by its JavaScript SDK.
Fillo is hosted and does not offer self-hosting. It fits a different moment: the form belongs on a route inside your product, rendered by your own components, and nobody wants to own a survey stack.
Formbricks publishes @formbricks/js on npm. Initialize it once with your workspace ID and app URL; from there it decides which survey to show and renders it, and you customize with CSS over what it draws.
import formbricks from "@formbricks/js";
formbricks.setup({
workspaceId: "<workspace-id>",
appUrl: "https://app.formbricks.com",
});With @usefillo/react, the fields are components in your own tree:
import { Fillo, when, createClient } from "@usefillo/react";
const client = createClient({ key: process.env.NEXT_PUBLIC_FILLO_KEY });
export function SetupFeedback() {
return (
<Fillo.Form id="setup-feedback" title="How did setup go?" client={client}>
<Fillo.Rating id="ease" label="How easy was setup?" max={5} required />
<Fillo.LongText
id="blocked"
label="What got in the way?"
visibleIf={when("ease").lt(4)}
/>
</Fillo.Form>
);
}Keep the default styles, pass your own class names, or swap a field for your own component. That visibleIf condition is data — a field ID, an operator, a value — so the same rule decides what renders and what Fillo's server accepts.
| Decision | Fillo | Formbricks |
|---|---|---|
| Operating model | Hosted; nothing to run | Open source; Formbricks Cloud, or self-host the database, object storage, and reverse proxy |
| Rendering in your app | Your React or DOM components, a fillo-form custom element, or a hosted page | SDK that displays Formbricks-rendered surveys, restyled with scoped CSS; link surveys by URL or iframe |
| File uploads | Connect a provider in settings; the browser uploads directly and Fillo verifies completion | S3-compatible storage you configure: environment variables, IAM policy, bucket policy, CORS |
| Working with responses | Grid, versions, CSV, Management API, signed webhooks | Your own instance, or Formbricks Cloud |
| Data residency | Fillo-hosted | Self-host to keep processing on your infrastructure |
Uploads are where the models diverge most concretely. Formbricks' file uploads documentation states that S3-compatible storage is required, and that the File Upload and Picture Selection question types stay disabled until it is configured: the S3_* variables, an IAM policy, a bucket policy, and a CORS rule without which browser uploads fail. The provider must also implement the S3 POST Object operation, and the same page names Backblaze B2 as incompatible for that reason. Checked against the self-hosting guide on August 6, 2026.
Fillo will not satisfy a self-hosting requirement, and it has no in-app targeting engine. It also starts a new response history: existing Formbricks responses stay where they are and cannot be imported with schema versions and delivery state. Fillo's transit storage is a starting lane, not a destination — 10 MB per file, 100 MB of active files per workspace, and completed files expire after seven days. Durable file workflows connect your own storage.
| Existing Formbricks setup | Expected work |
|---|---|
| A link survey shared by URL | Rebuild the fields as a Fillo form, then publish the hosted page or render it on your own route |
| An in-app survey with display rules | Decide where the form belongs in your UI and render it there |
| A self-managed S3 bucket | Connect the same storage in settings and retire the CORS, IAM, and endpoint plumbing |
| Webhooks into your backend | Reconnect each one, verify the signature, deduplicate on the delivery ID |
Open the editor and rebuild one real form on a route in your app before deciding about the rest.
Updated