Privacy rules still need good data modelling
Privacy rules need data they can trust
Privacy rules control which Things and fields a user can read. They work best when the data type has the fields needed to prove access directly.
The common failure is an ownership field being empty.
In a B2B app, you might have a Note data type with this privacy rule:
This Note's Organisation is Current User's OrganisationThat is fine if every Note always has an Organisation. If the Note's Organisation is empty, and the Current User's Organisation is also empty, Bubble can treat the two values as matching. For a logged-out user, Current User's Organisation is normally empty.
So an orphaned Note can become visible to logged-out users.
A safer rule is:
This Note's Organisation is Current User's Organisation
and
This Note's Organisation is not emptyOrphaned data should fail closed. If a workflow forgets to assign the Organisation, the Note should disappear from everyone, not become public.
Check the thing being protected
Write privacy rules against the Thing being protected. Do not depend only on Current User fields.
For example, if an Invoice belongs to an Organisation, the Invoice should normally have an Organisation field. The privacy rule can then check:
This Invoice's Organisation is Current User's Organisation
and
This Invoice's Organisation is not emptyThat is stronger than relying on a page condition, a role field, or a loose assumption that the Current User should only ever reach the right Invoice.
The protected Thing needs enough data to answer the access question. If it cannot answer that question cleanly, fix the data model before trying to patch the privacy rule.
Data API access follows the user context
The Data API can be called logged out, logged in as a user, or with an admin token.
For logged-out and normal logged-in requests, Bubble applies privacy rules. The API returns the Things and fields that user context is allowed to read. If Everybody Else can read a field, a logged-out Data API request can read it too.
Admin tokens bypass privacy rules. Treat them like keys to the database, because that is effectively what they are for Data API reads.
Before exposing a data type through the Data API, check:
what Everybody Else can read
what a normal logged-in user can read
what each role can read
where admin tokens are stored and used
Do not assume the Data API is protected just because the app has admin tokens configured. Without an admin token, the caller can still receive whatever privacy rules allow for that caller.
Return yes/no when yes/no is all the page needs
If the page only needs to know whether a record exists, do a backend check and return a narrow result.
For example, suppose a signup form needs to check whether an email already exists. Do not expose a searchable list of Users or Form Submissions to the browser just to answer that.
Use a backend workflow or backend custom event to check the email server-side and return:
exists: yes/noThe workflow may need elevated access for the search. That is fine if the returned data stays narrow. The page asked "does this email exist?" It did not ask for the matching User.
This pattern also works for invite checks, permission checks, and "can this user access this record?" checks. Return the decision, not the data behind the decision.
Lists used for privacy rules still load with the thing
A field used only in privacy rules is still a field on the Thing.
For example, a Project might have a Collaborators list used in a privacy rule:
Current User is in This Project's CollaboratorsThat can be a reasonable model. It is simple and easy to read.
The catch is that when Bubble returns the Project, the Collaborators field can come with it even if the page does not display the list. A large list used only for privacy rules can still affect loading, especially if the app filters or compares that list.
I would not avoid helper fields by default. I would avoid huge copied lists where a separate Membership data type would be clearer.
For example:
Project with 5 collaborators: a list on Project is probably fine.
Workspace with 20,000 permitted users: use a Membership data type and model the access properly.
Test privacy rules as the user
Test privacy rules by checking what each user can actually search.
A page looking correct is not enough. The page may hide the data while the privacy rules still allow the user to read it.
For important data types, test as:
logged out
a normal logged-in user
each elevated role
One simple manual test is a private admin-only test page with repeating groups for the relevant data types. Set each repeating group to Do a search for [Data Type], display the fields you care about, and load the page as each user type.
Anything visible there is allowed by privacy rules. If a logged-out user can see orphaned Teams, Notes, Invoices, or Users, fix the privacy rule and the data model.
Rule of thumb
Privacy rules should read like a direct permission check on the Thing:
This Thing's Organisation is Current User's Organisation
and
This Thing's Organisation is not emptyIf the rule needs a long chain of assumptions, the data model probably needs work.