Official Page Level Security Recommendation from Bubble

Hello all, especially @emmanuel and @josh

I have a fundamental design question related to page security. In most web based application frameworks I am used to the general design for security is that regardless of what methodology you use for assigning permissions, the page ultimately evaluates said permissions and sends you on your way if you don’t have them. It does this BEFORE the page actually loads, all “server side”.

Obvsiously there are all sorts of exceptions to that. Sometimes a page loads and parts of the page (components, etc.) have indepdndent permission checks, but still, it is all done before a single visible action happens.

If the application has a more client side design/single page architecture where every loads to the lient and then displays according to permission checks that happen post server, the framework inevitably allows the client components to come across the wire hidden by default.

Here is what I am seeing with Bubble (and I indicated this in a previous post

that never got traction as well as a bug report). You can do a workflow redirect but it happens after the page loads so elements can be seen that may contain data, so your solution is to hide everything on the page for load and use conditional “is page loaded” logic to show everything and then process your redirect workflow before processing your conditionals, except, you have no control over when conditionals evaluate vs. workflows, so this is not a bulletproof solution.

You can do the same thing as above but set the conditionals to check a page level custom state (say shouldLoadPage) that defaults to No and then use workflow to evaluate your permissions and set the page state to Yes if permission exists.

And yeah, that might work, but custom states are page level so you have to create one for every page, and put the same workflow logic in every page and write a special conditional for every group on the page or put a single gourp that holds all your other groups and write the conditional for that…phew.

What a mess. I read another post where someone said “I create an interstitial page that does the checking first”. Yuck.

It all seems…so hacky.

So what is the recommended way to do page level security in Bubble? Is there some reason there is not a simple, reliable way to redirect before everything loads like most frameworks allow?

Am I missing a way to do this that is simple and logical and not just a “I found a workaround that I like”?

If not, shouldn’t there be?

I think Bubble is amazing, and I know that a lot of the problems I have had over time have been because of my inability to adapt to the Bubble way, but what I have always been happy with is that when I do take the time to shift my mindset, I can usually find a solution or I can count on someone in the Forums to have found one. That is wonderful. But I can’t seem to see my way around this one.

Can anyone, especially a representative from Bubble, comment on this?

Many thanks in advance, as this one has been frying my brain for a while.


*Note - I know about Data Priacy but it doesn’t seem to be a solution for THIS issue.


Just to provide information to others who may suffer from the same issue I am having and are looking for solutions (even hacky ones) I want to share what I have done since this post.

First, I decided to take advantage of the fact that I have a shared header on all of my pages, to minimize the copy and pasting I thought I would have to do, and it almost worked. My header is only 60px high, but I discovered that Bubble doesn’t care about that and you can add items to your page that are at coordinates that are “off page”. So I tried this:

1. Created a group called “loading” in the header that was as big as my application (minus the header size), brought it to the front (I would be nice to be able to know what the Z-Index of a given item on a page is in the editor) and then I set it to be visible on page load. I then created a YES/NO custom state in the header page called “hideLoadingGroup” and I set a condition on the loading group to become invisible if the custom states was set to YES. I also set the loading group to collapse if it wasn’t visible.

2. The I went to every page I had. These pages already had Permission Check action, so right after that I put in an action that set the header’s custom State, hideLoadingGroup, to TRUE. The permission check redirects the user so if they don’t get passed it, the loading group that hides the whole page never disappears, if they do make it past the check, voila, the page appears.
a. One limitation in Bubble with regards to this is that when copying and pasting from one page to another, the action “lost” reference to the header item, even though every page calls it the same name. It would be nice if it could be smart enough to figure that out because instead I had to paste and then edit the action anyway.
b.Another nice feature to have would be to have SHARED custom events - Every page I have has a few actions that are exactly the same or only different in a single way. I could do an API call but I need it to be serial and not asynchronous.

Anyway, while being a hacky work-around, this seemed to do the job…until…I tried to use the responsive editor on one of the pages. The regular editor worked fine. But the responsive editor said “hey, there is a group that is covering everything else, so you can’t edit any of the objects on this page and btw, since it is coming from a shared component, you can’t even control the visibility.” So yeah, that was a non-started. Every time I wanted to edit a page, I would have to go to the header shared element and hide the loading group. So back to the drawing board.

I slept on the problem and this morning I deleted the loading group from the header and did the most annoying thing. I created a group on one of the pages, again called loading, set all the same parameters and conditions such that it would start visible covering everything else and then in response to a custom state it would become invisible. I tested that the responsive editor didn’t care about this (it doesn’t) and then…I had to copy the group…to…every…page. And on every page I had to edit the condition because, as noted above, Bubble can’t maintain the reference to a shared object across pages.

So yeah, I have a working solution now. So long as I remember that every time I add a new element to a page to make sure the loading group is at the very front, this should work.

But seriously, it shouldn’t be this hard. There are any number of ways Bubble could implement this, but something along the line of “Redirect before page load…” would be nice.

If I find a way to make this even easier, I will post my results.



I desisted months ago. I also opened 2 or 3 threads on exactly this same issue but the responses I got did not help in any way. I started to doubt if I was not able to explain the issue correctly because the replies I got is that I should hide group content that should not be shown and make sure data privacy is solid.For me this was not efficient and I was not happy that people could access backend pages and see the structure, even if they couldn’t see the contents. Imagine if you could access WordPress admin pages without content. You would immediately think…“wow this piece of software is not secure”.

Because UX wise what any normal user would expect is that if you try to access an admin page is that he gets redirected to index, to 404, to an admin login screen or an error authorization message. Anything but loading a page without database content but still showing static text and structure.

BTW the best option from a security perspective is to redirect to 404. Induce the user to think the page doesn’t even exist.

In the end I proposed the exact same thing as you: a Do before loading workflow. It got rejected. I still don’t know why would it be so difficult to implement something like that. I’ve had people poke in the admin backend of some apps

I’m just hoping that when Bubble releases the server-side actions plugins I can build a plugin for authorization checks. Because for me it’s the biggest pain I’m suffering.


@JonL - I hear ya but there is no reason a plugin should be necessary to get standard application security capabilities.

As for my continuing saga, it turns out that my idea of putting the blank group on every page also didn’t work.It sometimes (I could not piece together why it was only sometimes) screwed with the responsive-ness of the page. On some pages the blank group prevented me from seeing the box model of the other elements; but only on some pages.

So I had t undo that and go the route of putting a base group on every page that every other group sits in. I started out setting it to not be visible on page load, but that meant that every time I went to edit my page, I had to first make it visible in the element tree. (Note - a nice feature for Bubble would be an easier way to see all the elements on a page, hidden or not, when editing. Some “Turn on XRay View” switch that showed everything with their z-indexes…I don’t know, but something. And maybe the ability to set a preference for defaulting it to on)

Anyway, that annoyed me so I changed it to being visible on load with a condition that hides it if a custom state called showPage is set to No and I make the first workflow item on page load to be setting that custom state to No and then I do permission evaluations and set it to Yes if they pass. Now, this is what I tried before and I had times where the page flashed and content was available, so I am not sure why it is now working better. Perhaps some improvements have been implemented in the last couple of months. I will see how it goes and report back.

Sadly, I have heard no official response from anyone at Bubble.



I was just about to post a question regarding best practices for access control and page-level security. If, for example, someone attempts to visit a page reserved for logged-in users, is there a way to “return” a 404 (or 401), or is the only option to redirect to another page within the app?

I discovered a feature that works all at once. Just define an independent workflow like “When current user isn’t logged in => redirect to …”