This section covers security on pages, elements and workflows
In principle, every piece of data that reaches the user's device is no longer secure. As long as you are only sending data that the user should have access to, this is not a vulnerability but the only way your app can work.
If you are new to Bubble or web development in general, it's not necessarily obvious what this entails, so in this article, we'll have a look at the precautions you should take to avoid sharing more data with your users than you intended.
Think of the page as a bank and app's data types as a collection of safety deposit boxes. If a user gets access to the bank (page), the private information is still safely contained within the safety deposit boxes (database), and they are all locked (privacy rules).All the intruder sees is the lobby.
These files contain code that allows your app to communicate with the Bubble server, and send and receive data and commands between the two computers (your user's device and the Bubble server).
These files are stored on the user’s device, and a tech-savvy user can open up the downloaded files and look at the code. This is not in itself a vulnerability, but it means you as a Bubble developer need to be mindful of what kind of data you place in that code.
As a no-code platform, Bubble automatically generates the code for your app, which can inadvertently introduce vulnerabilities if you're not cautious about the information you store in your pages.
Option sets are a useful way to store static data that you can reference anywhere in your app. Option sets are downloaded along with the rest of your app's code and is decrypted and stored as plaintext on your user's device. As such, you should never place any sensitive data in an Option set. This includes the name of the set itself, and its different options and attributes, as well as the data stored in them.
The app text feature found in Settings - Languages is a useful way to translate static text strings so that your users can see your app in different languages. Bubble downloads the strings that are relevant for the current user’s language. These strings should not be considered secure: never store sensitive information in app texts in any language.
Whenever you store static data in an element, you should assume that the data becomes part of your application's code. For example, let's say you place a text input element on the screen that has the Placeholder text "Name", that placeholder will be visible in the app's code.
Avoid placing any kind of sensitive information in your elements, even if they are hidden on page load.
Bubble downloads the name of all your pages on each page load. In other words, even if a user is just loading one page, the code still contains the name of all other pages. Don't give your pages names that contain any sensitive data, and don't assume that a page that you are not linking to is secure – a user looking at the app's code can identify the names of each one.
You can also consider giving important, secure pages names that differ from the norm: for example, a page called admin or login may be targeted by bot networks simply because it shares such a widely used label. If you use a more uncommon name, you may avoid the wide net that's cast looking for standard names.
Bear in mind that while this adds a layer of obscurity, it shouldn't be seen as a standalone security measure. It will not stop an unwelcome visitor from finding the page, but may make it slightly more difficult.
Just like with elements, when static data is stored in workflows, it becomes a part of Bubble's codebase. Some data is sent to the user's device when a workflow's result is processed, and this information might become accessible on that device. This includes any data kept in an element's state during the workflow, as these element states reside on the client side.
Additionally, the IDs (but not the fields) of objects that the workflow altered are included. These IDs are necessary to ensure that the changes are immediately visible in the browser. While this data sharing is part of the regular function of the web app, it's something to be aware of as you manage what information is passed between the server and the client.
The following information about all data types is also visible in the code:
- The name of each data type
- The name of all the fields saved on all data types
- The default value of those fields as specified in Data - Data types
The data that you store in these data types in the database are encrypted and secure while in storage.
The API Connector allows you to set up different calls to be used in actions and as data sources. The following information will be visible in the app code:
- The name of each call
- The key and value of each parameter, unless they are set to private
- The URL of each call, unless you specify the URL in a parameter by using 
When you delete one of the things specified in the header, they are not permanently deleted, but are kept around in case you want to undo the action. You can clean out this deleted info by using the Optimize app feature.
Using the Optimize app feature lets you completely remove deleted fields, data types, options sets and attributes.
To access the Optimize app feature, go to Settings - General and click the Optimize app button.
Conditions can be processed directly on the client or needs to involve the server, depending on the dynamic expression that you use. If you use a condition on an important workflow event or action, it's more secure to set up a condition that involves the server; that way, the processing is done out of reach of the user.
To make sure a condition is processed server-side, you can involve anything having to do with the database or user authentication. For example, Current user is logged in and Do a search for:count > 0 are both conditions that Bubble will query the server to process.
Additionally, if the condition is placed on a server-side action, both the condition and the action will be processed on the server. The exception is if the condition can't be processed on the server. For example, Element X is visible needs to be checked on the page, and can result in a more vulnerable condition.
Redirecting users from one page to another can be done in two ways:
- Client-side redirects occur directly in the user's browser. When a certain condition is met or an event occurs (like clicking a button) and the Got to page action runs, a script running in the user's browser will change the current URL, causing the browser to load a new page. This happens without any interaction with the server.
- Server-side redirects, occur when the server responds to a request from the browser by instructing it to load a different page. This too is done with the Go to page action, but only under the following conditions:
- It happens before the page has loaded
- One of the events below triggers the redirect:
- User is logged in
- User is logged out
- Page is loaded
- The workflow contains only one action (Go to page)
It's important to keep in mind that while you should try to ensure server-side redirects for secure pages, all data and workflows on the page still need to be protected by Privacy Rules and conditions.
In principle, everything that reaches your user's device is no longer encrypted and private, but is stored as plaintext on that device. While it may not be visible to most users, a tech-savvy user can open up the downloaded files and track the data coming and going through the network to see its content. This is why it's important to:
- Set up privacy rules for all data types and fields that are private
- Never store sensitive data like personal information and API keys in elements, events, actions or conditions
- Set up server-side redirects to guide users away from pages to which they shouldn't have access
- Treat the page as a bank: it may be closed, but if people manage to break in, all the valuables are still locked safely inside locked safety deposit boxes