There have been a lot of forum posts about SEO on Bubble. From content around on-page technical SEO optimizations using semantic html markup e.g using Header tags (h1, h2, h3) to concepts such as page load speed and more around the like. What I want to do with this series of forum posts (potential series based on feedback) is provide a mental model that should (hopefully) help people build apps that can rank on search engines for their own competitive keywords (in their respective niches). In addition to providing a straightforward mental model, I’m also going to provide examples and ideas that people can use to, hopefully, improve their SEO for their respective bubble apps (or even consider it as a channel at all). Having a solid mental model in place for what’s going on can help you make more informed decisions about any SEO intervention that you read or hear about on here. Each section of the mental model will also have tips that you can immediately implement to help your bubble app. This is part 1. where I get into the crawling aspect of the search pipeline. Let’s get on with it.
Why SEO (Skip if you already know)?
When building any digital product, you’re going to have to answer the question of how people are going to discover your product. Search engines such as Google or Bing are a prime opportunity for people to discover your content. When a user enters a particular query( also known as keyword) into Google, Google serves them with results that it believes will solve that user’s intent. If your product’s content starts to rank high on Google for that query (in the top 3 results on the page) then there is a high likelihood that someone will click on the result and head over to your digital product’s content. This gives you a chance to convert that user into a paying customer. Using SEO can be a cheaper method of acquiring customers than running ads to acquire that user. The field of SEO was basically developed to help optimize web content so that they would show up higher in the results page for various search engines and queries.
The Breakdown
- The search pipeline: The overview of how these search engines operate
- The Search Engine Results Page (SERP) is a product
- What are the search engines rewarding?
- What do the potential customers in my niche actually care about?
The search pipeline:
There are really three components to what these search engines are doing. They can be broken down into:
- Crawling - how search engines and other crawlers discover and crawl content (What we are covering in this post)
- Indexing - what content is stored by these search engines within their index
- Ranking/Serving - The processes that take place for ranking your content on a search engine’s result’s page for a specific user query/keyword.
Crawling
What is it: There’s no central directory of all websites that exists. So these Search engines have to be able to find new (as well as updated) content across the entire web platform (almost an infinite space) and add them a list of their known pages. These search engines use crawlers, basically an automated program, that goes to your page and downloads that page’s. content e.g images, text, videos etc. We can think about crawling in roughly two stages; discovered and crawled. Lets use Google as an example (one of It’s crawler is named Googlebot). Googlebot fetches another website’s content and parses it. This website has a link to your bubble app (https://yourapp.com). Googlebot places this link in a discovered queue of sorts → “Hey we found this link”. Once Googlebot discovers a link, it may crawl (fetch/download) that page to find out what’s on it (but it’s not guaranteed). Googlebot uses an algorithmic process to decide which link (URL) to crawl; how often the link should be crawled; how many pages to fetch from each site.
What’s factors are in your control as a Bubble Dev:
- Page Size/Speed (to some extent)
A lot of forum posts have been dedicated to page size/speed when it comes to serving/ranking a webpage; it’s also important for crawling since Googlebot can render a page (basically converting raw HTML, CSS and Javascript into an interactive page). Key considerations you should try and apply to reduce this:
(A) Use the “:processed with Imgix” operator on most images to reduce an image’s quality (especially the ones that are visible to search engines). This will be especially helpful if your app has user generated content where external users are adding unoptimized images to your app.
(B) Use an image compressor (tons of free ones like: https://imagecompressor.com/) to compress your images before uploading them to your bubble app. This reduces the total download size of these images. This can be useful if you have some blog content and want the images to not be as heavy when loading the page.
(C) The resources that Bubble has around WU optimization works well for optimizing Page Speed/Size of your bubble app (with a focus on page loads and searches) from Bubble’s manual here
- Few examples, e.g try to defer some searches by using a condition on some elements, e.g a Repeating Group, that uses a condition such as “Page is loaded” to then provide a data source for that group. You can also do some interesting things such as using the current page scrolling position as a condition for when data should be loaded into the container (e.g Repeating Group) to prevent that search from being downloaded on page load etc.
(D) You can use lighthouse (A tool from Google) to measure the page load of your app. You can download the extension or if you use the chrome browser, you can open up chrome devtools and head to the lighthouse functionality in incognito mode. You can then use that to generate some diagnostics on how your app is performing; the report gives some guidelines on things to improve:
(E) Note: Bubble uses a lot of javascript to create a page on the user’s browser so there may be performance costs (think about it as some level of overhead costs) that may be applied to your bubble pages. However, how you optimize your app also plays a big part into this cost. Additional note: Googlebot only downloads and render the first 15mb of a downloaded resource (page) before sending the content off to be indexed.
-The Robots.txt
This is your way of signaling to crawlers what should and should not be crawled. Bubble creates a Robots.txt file (basically a text file) for you however you can choose to create and add your own (simply head into your editor, go to settings, then to the SEO section, and then click on the customize robots.txt checkbox).This file will be stored at the root of your app e.g https://yourapp.com/robots.txt Bubble has documentation on how to set up a Robots.txt file so I won’t go too deep on that. Here are some things that might be useful to know:
(A) Googlebot, keeps a cached (saved version) of your app’s robots.txt file and updates it every 24 hours during its crawling process
(B) The robots.txt file talks to crawlers via rules that apply to all crawlers or a specific crawler. some elements of these rules are as follows:
-
“User-agent:” this specifies the specific crawler e.g Googlebot, or you can use regex to define all crawlers such as “User-agent: *” the * is basically a wild card that matches to all crawlers.
-
“Disallow:” this basically tells the crawler not to crawl specific pages/resources. If you have a list of resources you don’t want crawled by a crawler, then each of those pages would need to have their own “Disallow:” line within the robots.txt under the specific User-agent line. For example:
- User-agent: *
- Disallow: /forgot-password
- Disallow: /rooms/
- Disallow: /info-that-should-not-be-crawled
One thing to note is that the disallow line uses relative URLs, so if your app is https://yourapp.com using a disallow link to not crawl the forgot password page. “Disallow: /forgot-password” would basically block Googlebot from crawling “https://yourapp.com/forgot-password”. We can use regex to set up some pretty complicated rules, however that’s out of the scope for this post
-
“Allow:” Think about this as the escape hatch, from the “Disallow:”, that is provided to you so Googlebot (and other crawlers) can access specific parts of your app. E.g If I block Googlebot from accessing “/rooms” but there’s some specific resource on the rooms page that I want Googlebot to access, then I’ll use the allow rule as follows:
- User-agent: *
- Disallow: /rooms/
- Allow: /rooms/bigger-rooms
So we are allowing Googlebot to access https://yourapp.com/rooms/bigger-rooms even though it’s blocked from crawling the /rooms/ directory.
*“Sitemap”: This tells google where your sitemap is located e.g
- User-Agent: *
- Disallow: /version-test/
- Sitemap: https://yourapp.com/sitemap.xml
- As an interesting exercise to see the numerous amount of crawlers that you can target via the robots.txt, I would recommend checking the robots.txt of specific companies. I’ve screenshotted two below. They are for Airbnb and Alltrails (These websites have a lot of content via listings or trails; a lot of user-generated content). You can access their robots.txt files at https://airbnb.com/robots.txt and https://alltrails.com/robots.txt
- From the screenshots below we can see that Alltrails is blocking a bunch of crawlers including “Anthropic-AI” which is very interesting; they’re explicitly telling Anthropic to not crawl its website.
- You can learn a few interesting tidbits by analyzing the content that some of these sites want (and don’t want) crawlers to crawl.
- From the screenshots below we can see that Alltrails is blocking a bunch of crawlers including “Anthropic-AI” which is very interesting; they’re explicitly telling Anthropic to not crawl its website.
-Sitemaps:
(A) You can use sitemaps to encourage crawling by helping Googlebot discover the pages that you want crawled (Remember discovery does not mean the resource will be crawled). These sitemaps are primarily XML sitemaps (sitemap.xml) that can be submitted to Google and also referenced in your robots.txt. Some major sites use both HTML and XML sitemaps. E.g in incognito mode of your browser of choice, head over to LinkedIn, https://www.linkedin.com and scroll all the way down to the footer, you will see they have a directories column, clicking on “people” will take you to an HTML sitemap (https://www.linkedin.com/directory/people)). You can build your own HTML sitemap if you want but there’s no clear consensus on the benefits of this approach, so an XML sitemap is your go-to approach in my opinion. Sitemaps are located in the root of your app e.g https://yourapp.com/sitemap.xml
(B) There are two relevant types for most bubble devs in my opinion. There is the sitemap and the sitemap index. A sitemap contains a list of URLs, and the sitemap index contains a list of sitemap URLs. Fortunately for a majority of Bubble Devs, Bubble can dynamically set this up for you. Simply head over to the editor, navigate to settings, and then head to the SEO section. Within that section, you can expose a sitemap, and choose the different page types that you want bubble to place within the sitemap.
This generates the sitemap index below (Note it’s a sitemap index; so it’s a list of sitemaps since Bubble dynamically generates sitemaps according to the pages you’ve chosen to be included in the sitemap. If these pages have a type then Bubble will create a sitemap for them e.g https://yourapp.com/sitemap-product.xml for my product datatype)
Copying the content between the tags of your sitemap index for one of the dynamic types e.g Products from the screenshot above will take you to the sitemap itself. Screenshot below:
This is perfectly fine, though there is one issue from an SEO point of view from the screenshot above, the <lastmod> tag is missing. Within every <url> tag there should be a <loc> (location tag) as well as a <lastmod> (last modified) tag. This tag has the format YYYY-MM-DD so <lastmod>2025-06-08</lastmod> and it basically helps search engines know which pages have fresh/updated content and should be prioritized for crawling. This is important. It’s a verified signal that Google and other search engines have openly shared as part of the ways to signal priority for crawling from their respective crawlers. Additionally, search engines use this tag to establish a baseline for how often they should crawl your site. For example, Google uses the tag by comparing the link’s content at that date to the last date it has, and seeing if there were significant changes from the last resource it has in its index at that date. Do not abuse this tag, only use it for significant changes (defined as changes to your main content, structured data, or even links on the page).
Some Bubble plugins allow you to create your own sitemap however they use the <priority> (priority) tags which have long been deprecated/ignored by major search engines such as Google. So if you go the route of creating your own sitemap to help with crawling, definitely add the <lastmod> tag (If you’re implementing a single page application; then you should probably create your own sitemap.)
-Link Structure:
(A) Search engines need links to discover your content. You have to make sure that your links are crawlable. In bubble, this principle means that the link block element is your friend when it comes to SEO. Use that element within your pages to make sure that Google can discover and crawl links when Googlebot is on your app.
(B) If you do use the link block element within your app, make sure that the content you provide is descriptive of the resource (Screenshot below). When crawling, google extracts this text and uses it as a signal to understand what the resource (page) is about.
(C) General guidelines for link structures are as follows; use hyphens for your links. So instead of https://yourapp.com/product/greendress you should use https://yourapp.com/product/green-dress .
(D) If you have an app where users can submit content and links to pages that are visible to crawlers then I would recommend marking all those links as nofollow links ; especially if you don’t trust the users (Screenshot below). This is important because your app basically has a score (think about it as Google’s understanding of how trustworthy you are; a bit of a simplification but a useful one), linking to spammy websites reflects negatively on you if you don’t have the nofollow setup on the link elements you use. If you have an app where users are adding links to profile pages or listings, I’d strongly recommend implementing this. It basically tells Googlebot to ignore following the link to that website which preserves your score
(E) Note: I’ve seen somewhere that Google does not like URL parameters. That is true to an extent; though it is a bit of a longer post with nuances to it. So I might schedule it for a later post.
I hope this post helps! I’ll be adding more posts if this is genuinely helpful to people, and helps them learn things that they can immediately implement to help.