Require Login To View Page?

First: You don’t have to navigate the user/agent away from the page.

Second: ATM, you can’t have exactly what you desire, because this is just the way Bubble implements routing.

Third: You can do what other web apps do, which is to not actually navigate at all, but to emulate navigation. (read on)

Could Bubble implement routing by a different method? Sure, but then that would be a different interface and Bubble is designed with this metaphor of access control being associated with “actions” on a page.

[Aside: In an environment geared toward users who know little-to-nothing about how the web works (much less web applications) I can only imagine the questions that would crop up here in the forums and that alone is reason enough to not desire such features.]

You will note that we do not have any sort of granular server control in Bubble (examples: granular control of allow X-Frame-Options, you can’t have myappurl.domain/[user_id] etc., etc.). It’s just not a thing.

The “stack” for your Bubble app does not have its own server (unless you are on a dedicated plan – and even then, you probably don’t have control over it through any UI, though you probably can have Bubble configure it for special requests). You share a cluster with many other apps – there is some sort of serving/routing that decides, when a request comes in for some URL (either a page in your/somebody else’s app or your/somebody else’s API endpoint) that decides when the response will be served.

And neither is there a concept of a “virtual router” in your app beyond the design of your page flows. (Though it’s worth noting that a Bubble app’s folder hierarchy is flat – there are no subfolders, e.g., myappurl.domain/products/best-brands-of-child-repellent is not a thing, right? So your “pages” may or may not be virtual, but they are probably virtual, so I guess we could have a fake routing interface, but see the point above and the point I am about to make below.)

Now, in today’s web, and in today’s development environments, some are familiar with the “fake” routing of things like React Router (which give you the ability to create a single-page app that seemingly “navigates” to new URLs but in fact stays put in the context of the current page, but that also allows the handling of incoming requests for these fake URLs).

Well, vanilla Bubble just doesn’t have that. At least, it’s not exposed in the way that things like React Router do it. (And building single-page apps in Bubble is so kooky that I’m surprised anybody does it, but to each their own, eh?)

However, the equivalent in Bubble is this:

As I said, you don’t have to navigate the agent away from the page. You can include your login element in a resusable on the page. In the classic Bubble template, there’s a great example of this. The login/signup dialog is a reusable that is, itself, included in the reusable page header, so all your pages can be “/login” if you choose to tweak it a bit.

How can you do this?

Well, for authorized-user-only-pages you group everything except for the header in a group that is not visible on page load (the smart way to do this is create your starting template page with a group on it and build all your shit in that group, NOT in the page object – in the demos I link to below, this group is given the HTML ID PAGEGROUP). This group, of course, is NOT visible on page load.

And then, on page load, you evaluate “user is logged in” / “user is not logged in”. If the user is logged in, you show the “page group” (I usually call this group something like “Page Proxy”).

If the user is not logged in, you SHOW THE LOGIN POPUP. For extra credit you can do the same stupid shit that React Router does and change the visible URL in the browser’s nav bar to whatever/login (in the demo linked below I’m using Copilot’s “Browser” plugin, which I don’t find any faults with - it’s just a nice, clean interface to the browser API we need to interact with here to do this).

Once you do that (create “fake” /login pages) you should actually create page /login so that if some smartypants refreshes their browser, they will land on the ACTUAL /login page.

I’m not gonna type out how you do all that here, but just point you to a sample:

Run Mode – You have to sign up/log in to access this page:

When you get there, you will note that it seems you’ve landed on a page called /login. But you haven’t. Of course, if you refresh your browser, you WILL wind up on /login. (So we gotta create a real page for /login in Bubble if we’re gonna fake this easily.)

But don’t do that. Don’t reload the page. Just signup/login and watch what happens. Without REALLY navigating you to another page, all of a sudden the hidden page group gets added to the DOM, AND the apparent URL changes to the original page you requested.


(Note: Does that sound hinky to you? It’s literally how zillions of web apps built with code work. So which is hinky: the Bubble way or the React Router way? :thinking: Answer: Neither – it’s just how web apps work.)

Edit mode for this demo page (“you-gotta-log-in”):

Edit mode for the Header element, where some of this magic needs to be handled (displaying the login popup if we’re on the you-gotta-log-in or login pages… we wouldn’t need to “conditionalize” that if we were doing this for every page in our app, we would instead adopt conditions for the pages on which we DON’T require the user to be logged in, right?):

Edit mode for the real /login page (to handle the case if the user lands on a login-only page, and we rewrite their URL and they then refresh):

Please note: the sample app here is one of my demo apps for List Shifter. It was not designed to do the right magic on all the pages and, besides the demo page(s) I’m talking about here, is not designed to fake URLs all over the place. I just did this quick lil’ demo to help you understand. (Also, having done it, I kind of like this approach and might adopt it in real apps, so there’s that.)


  1. Some stuff that seems hinky is actually the way things work in real life. (This can be said of just about everything in real life, amirite?)

  2. Despite your complaints, Bubble does real page routing. You just don’t have super-granular control over it. Also, said routing is brokered by a server or cluster of servers that are shared and - especially on free and lower-tier paid plans - it FEELS like request brokering is WAY TOO SLOW. [I’ve not seen the folks at Bubble address what actually happens here, so I’m educated guessing, but this is a frustration about Bubble in general and it would be interesting to know exactly how much capacity you have to buy to get priority. Hmm.]

  3. A lot of times, on the interweb, you think you’re being routed for realz, but you’re not. (Instead, the page is actually doing that and you’re not navigating in the true sense of the word. And we can do this in Bubble if we desire to.)

  4. It’s really hard to tell the difference between 1 and 2, beyond apparent speed. (And, done right, there should be no way for you as the user to know.)

  5. Rolling your own fake routing is kind of a pain in the butt in Bubble (hmm… is there perhaps a plugin opportunity here?), but to do it for a small set of pages isn’t that big of a deal, should you desire to. (I sometimes think of Bubble as a Rapid Development Environment, but then my hands get tired of all the pointing and clicking and I’m like “WHAT SADIST DESIGNED THIS???”)

  6. You might initially think that #4 is a strong argument for just saying “fuck it” and learning modern web app development with the tools that a million times more people use than Bubble, but really it’s all kind of the same. (And also you’re using Bubble because you realize that you can get quite a bit further along, quite a bit faster than having to learn everything about web development before you can even build “Hello World”. Also, if you think Bubble is crazy, just dig into modern front-end web development… it’s a fucking HAT full of crazy… but not without its advantages. :man_shrugging:)

  7. I did not call this out, but: BTW, remember that PAGEGROUP group I mentioned before? If you load the /you-gotta-log-in page without being logged in, you will note that PAGEGROUP element DOES NOT EXIST in the page. It’s literally not in the DOM yet. When we login, PAGEGROUP gets created. If we now logout, PAGEGROUP becomes not visible, but only because its CSS display property goes to none. That is, it is still present in the page but not being rendered.

(This would argue for doing a REAL navigate to some safe page on log out, rather than just faking the page’s logged out state. I’ve actually never tested that before and am a little surprised that the element is not destroyed. Practically speaking, this probably isn’t a big security risk, but it points out the importance of using privacy rules for protecting data, and not just visibility.)

  1. Related reading and exploration: Direct links for users?