Displaying external API data on Bubble pages requires more than just connecting the API — you need loading states, error handling, response caching, and refresh logic. This tutorial shows you how to create polished API-driven page experiences with Custom States for loading indicators, conditional error messages, cached responses, and manual refresh buttons.
Overview: Improving API Response Handling on Bubble Pages
When your Bubble app displays data from external APIs, the user experience depends on how you handle the space between requesting and receiving data. This tutorial covers building robust API response handling: showing loading spinners, displaying meaningful error states, caching responses to avoid unnecessary API calls, and giving users the ability to refresh data. These patterns apply to any API Connector integration.
Prerequisites
- A Bubble app with at least one API Connector call configured and initialized
- Basic understanding of Custom States and how to set them
- Familiarity with the Conditional tab for element visibility
- Understanding of Bubble workflow actions
Step-by-step guide
Create loading state indicators
Create loading state indicators
Select your page and add a Custom State called is_loading of type yes/no with default value no. Create a Group element containing a loading spinner (use a GIF image or an animated icon). On this group's Conditional tab, add: When page's is_loading is no → This element is visible: no. In the workflow that triggers your API call, add as the first action: Set state of page → is_loading = yes. After the API call action completes, add: Set state of page → is_loading = no. The loading group shows while the API is processing and hides when data arrives.
Pro tip: Place the loading group in the same position as the data display group and check 'Collapse when hidden' on both — this creates a seamless swap between loading and data states.
Expected result: A loading spinner appears while the API call is in progress and disappears when data loads.
Handle API errors with user-friendly messages
Handle API errors with user-friendly messages
Add another Custom State on the page called api_error of type text (default empty). Create a Group element for error display with a red background, containing a Text element showing page's api_error and a Retry button. Set this group's condition: When page's api_error is empty → visible: no. In your API call workflow, the Toolbox plugin's Run javascript action or the API Connector's error handling lets you detect failures. If using API Connector as an action with 'Include errors in response' checked, add a condition after the call: Only when Result of step X's status_code is not 200 → Set state api_error = 'Unable to load data. Please try again.' When the call succeeds, set api_error back to empty.
Expected result: When an API call fails, users see a friendly error message with a retry option instead of a blank or broken page.
Cache API responses in Custom States
Cache API responses in Custom States
Instead of calling the API every time a user visits the page, store the response in a Custom State. Add a Custom State called cached_data of the appropriate type (matching your API response structure). In your API call workflow, after a successful call, add: Set state of page → cached_data = Result of step X. Then set your display elements' data source to page's cached_data instead of directly to the API call. Add a condition on the Page is loaded event: Only when page's cached_data is empty — this skips the API call if data is already cached from a previous interaction on the same page session.
Pro tip: Custom States reset on page reload. For longer-lasting caching, store the response in a database record with a timestamp and only call the API when the cached record is older than your desired freshness threshold.
Expected result: API responses are stored in Custom States, preventing redundant API calls when users interact with the page.
Add manual refresh functionality
Add manual refresh functionality
Add a Refresh button (or icon) near your data display area. Create a workflow: When Refresh button is clicked → Set state is_loading = yes → Set state api_error = empty → Call the API action → Set state cached_data = Result of step 3 → Set state is_loading = no. This clears any existing error, shows the loading indicator, fetches fresh data, and updates the cache. You can also add automatic refresh using a 'Do when condition is true' event set to run every X seconds — but be careful with this approach as it consumes API calls and Workload Units continuously.
Expected result: Users can manually refresh API data with a button click, and the UI shows loading state during the refresh.
Display partial data with graceful degradation
Display partial data with graceful degradation
When an API returns complex nested data, some fields may be empty or missing. For each display element, add fallback text using the :default operator or a condition. For example, a Text element showing api_data's description should have a condition: When api_data's description is empty → change text to 'No description available.' For images, set a static fallback image that shows when the dynamic API image URL is empty. For Repeating Groups bound to API list data, add a condition: When the list count is 0 → show a 'No results found' message in a separate Text element.
Pro tip: For APIs that return inconsistent data structures, RapidDev can help build a normalization layer using backend workflows that standardize API responses before displaying them on your pages.
Expected result: Pages display meaningful fallback content for any missing or empty API response fields instead of showing blank spaces.
Complete working example
1API RESPONSE HANDLING — WORKFLOW SUMMARY2=========================================34CUSTOM STATES ON PAGE:5 is_loading (yes/no, default: no)6 api_error (text, default: empty)7 cached_data (API response type, default: empty)89UI ELEMENTS:10 Loading Group: visible when is_loading = yes11 Contains: Spinner/animated icon12 Layout: Collapse when hidden1314 Error Group: visible when api_error is not empty15 Contains: Error text (page's api_error), Retry button16 Layout: Collapse when hidden1718 Data Group: visible when cached_data is not empty AND is_loading = no19 Contains: Data display elements bound to page's cached_data20 Layout: Collapse when hidden2122WORKFLOW: Page is loaded (Only when cached_data is empty)23 1. Set state → is_loading = yes24 2. API Connector call (configured action)25 3. Only when step 2 succeeds:26 Set state → cached_data = Result of step 227 Set state → api_error = empty28 4. Only when step 2 fails:29 Set state → api_error = 'Unable to load data. Please try again.'30 5. Set state → is_loading = no3132WORKFLOW: Refresh button clicked33 1. Set state → is_loading = yes34 2. Set state → api_error = empty35 3. API Connector call36 4. Set state → cached_data = Result of step 337 5. Set state → is_loading = no3839WORKFLOW: Retry button clicked40 → Same as Refresh workflow4142FALLBACK PATTERNS:43 Text: condition → When [field] is empty → show 'N/A'44 Image: static fallback image when dynamic source is empty45 List: condition → When list:count is 0 → show 'No results'Common mistakes when improving API response handling within Bubble.io pages: Step-by-Step Guide
Why it's a problem: Not showing any loading indicator during API calls
How to avoid: Always implement a loading Custom State and a visual spinner that shows while the API call is in progress.
Why it's a problem: Calling the API on every page load without caching
How to avoid: Cache the response in a Custom State and add 'Only when cached_data is empty' condition on the API call event.
Why it's a problem: Displaying raw API error messages to users
How to avoid: Catch errors and display a friendly message like 'Unable to load data. Please try again.' Log the technical details to a database for your own debugging.
Best practices
- Always show a loading indicator while API calls are in progress
- Cache API responses in Custom States to reduce redundant calls and improve responsiveness
- Display user-friendly error messages with a retry option when API calls fail
- Add fallback values for every field that might be empty in the API response
- Log API errors to a database for debugging while showing clean messages to users
- Use 'Collapse when hidden' on loading, error, and data groups for clean layout transitions
- Set reasonable timeouts and add retry logic for unreliable external APIs
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
I'm displaying external API data on a Bubble.io page and I need to add proper loading states, error handling, and caching. Can you help me design the Custom State pattern and workflow sequence for robust API response handling?
Help me create a loading indicator and error handling flow for my API data display. When the page loads, show a spinner while the API call runs, display the data when it succeeds, and show an error message with a retry button if it fails.
Frequently asked questions
Why does my API data not appear immediately on page load?
API calls take time to execute. The page renders before the API response arrives. Use Custom States to cache data and a loading indicator to bridge the gap.
Can I cache API data in the database for longer persistence?
Yes. Create a Data Type for cached responses with a timestamp field. Before calling the API, check if a cached record exists that is less than X minutes old. If yes, use the cached data. If no, call the API and save the response.
How do I handle API rate limits on the display side?
Cache responses aggressively so you make fewer calls. Add exponential backoff in your retry logic — wait 2 seconds, then 4, then 8 before retrying. Display a message like 'Too many requests. Data will refresh shortly.'
Can I show a skeleton loader instead of a spinner?
Yes. Create gray placeholder boxes that match the layout of your data elements. Show them when is_loading is yes and hide them when data arrives. This gives users a preview of the page structure while loading.
What happens if the API response structure changes?
Your API Connector call needs to be re-initialized with the new response structure. Go to Plugins → API Connector → click the call → Re-initialize. Update any data bindings that reference changed fields.
Can RapidDev help with complex API integration patterns?
Yes. RapidDev can architect robust API handling patterns including retry logic, response normalization, multi-API aggregation, and optimized caching strategies for data-heavy Bubble applications.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation