# How to extend Bubble.io with custom functionality: Step-by-Step Guide

- Tool: Bubble
- Difficulty: Beginner
- Time required: 20-25 min
- Compatibility: All Bubble plans (some features require paid plans)
- Last updated: March 2026

## TL;DR

When Bubble's built-in features are not enough, you can extend your app with JavaScript plugins, custom HTML elements, external scripts, and the Bubble API for server-side processing. This tutorial shows you how to go beyond Bubble's defaults safely, covering the Plugin Editor, HTML elements for custom code, and when to offload processing to external services.

## Overview: Extending Bubble with Custom Functionality

Bubble handles most app-building needs visually, but sometimes you need functionality that does not exist as a built-in feature or marketplace plugin. This tutorial covers your options for extending Bubble: injecting JavaScript through HTML elements for quick customizations, building custom plugins for reusable functionality, loading external libraries, and using external APIs for processing Bubble cannot handle natively. This guide is for builders who have hit Bubble's limits and need to go further.

## Before you start

- A Bubble account with an app
- Basic understanding of what JavaScript does (optional but helpful)
- Familiarity with Bubble's Design and Workflow tabs
- Understanding of the Plugin tab and how plugins work in Bubble

## Step-by-step guide

### 1. Add custom JavaScript using an HTML element

In the Design tab, click the + icon and search for HTML. Drag the HTML element onto your page. In the element's Property Editor, you will see an HTML content area. Type your JavaScript wrapped in <script> tags. For example: <script>document.addEventListener('click', function(e) { if(e.target.matches('.copy-btn')) { navigator.clipboard.writeText(e.target.dataset.text); } });</script>. This adds copy-to-clipboard functionality. The HTML element renders directly in the page, so your script runs when the page loads. You can also add CSS styles with <style> tags for custom styling that Bubble's design tools do not support.

```
<script>
  // Copy to clipboard when a .copy-btn element is clicked
  document.addEventListener('click', function(e) {
    if (e.target.matches('.copy-btn')) {
      navigator.clipboard.writeText(e.target.dataset.text);
      e.target.textContent = 'Copied!';
      setTimeout(function() {
        e.target.textContent = 'Copy';
      }, 2000);
    }
  });
</script>
```

> Pro tip: Use the HTML element sparingly. Each one adds overhead to the page. Consolidate multiple scripts into a single HTML element when possible.

**Expected result:** Custom JavaScript runs on your Bubble page, adding functionality beyond Bubble's built-in capabilities.

### 2. Communicate between JavaScript and Bubble using the Toolbox plugin

Install the Toolbox plugin from the Plugins tab (search for 'Toolbox' — it is free). This plugin provides a JavaScript to Bubble element that lets your custom code send data back to Bubble workflows. After installing, drag a JavaScript to Bubble element onto your page. In its settings, define output values (e.g., result_text of type text). In your HTML script, call bubble_fn_result_text('your value') to pass data from JavaScript to Bubble. You can then use this value in workflows by referencing the JavaScript to Bubble element's result_text. This is the bridge between custom code and Bubble's visual logic.

> Pro tip: The Toolbox plugin also includes a Run javascript workflow action and a Server script action for running JavaScript in backend workflows.

**Expected result:** JavaScript code can send data to Bubble, and Bubble workflows can read values returned by custom scripts.

### 3. Load external libraries via the page header

Go to Settings in the left sidebar, then click the SEO / metatags tab. Scroll to the 'Script/meta tags in header' section. Here you can add <script src='...'> tags to load external JavaScript libraries on every page. For example, to load a charting library: <script src='https://cdn.jsdelivr.net/npm/chart.js'></script>. For page-specific scripts, use an HTML element on that page instead of the global header. After loading the library, you can use it in HTML elements on your pages. Be cautious about the number of external scripts — each one adds to page load time.

**Expected result:** External JavaScript libraries are available globally across your Bubble app for use in HTML elements and plugins.

### 4. Create a custom plugin for reusable functionality

Go to bubble.io/home/plugins and click 'Create a new plugin.' Name it and add a description. In the plugin editor, you have tabs for Elements, Actions, and API calls. To create a custom action: click Actions → Add a new action. Name it, define input parameters (e.g., text_input of type text), and write the JavaScript code in the code editor. Use the properties object to access inputs (properties.text_input) and the context object to return results. Click 'Install on app' to add your plugin to your Bubble app. The action now appears in your Workflow editor under Plugins.

```
function(properties, context) {
  // Example: Format a phone number
  var phone = properties.phone_number.replace(/\D/g, '');
  var formatted = '(' + phone.substr(0,3) + ') ' + phone.substr(3,3) + '-' + phone.substr(6);
  return { formatted_phone: formatted };
}
```

> Pro tip: Keep plugins focused on one task. A plugin that formats phone numbers is easier to maintain than one that formats phones, emails, and addresses.

**Expected result:** A custom plugin action is available in your workflow editor, providing reusable functionality across your app.

### 5. Use the Bubble API to offload heavy processing externally

For tasks Bubble cannot handle efficiently — like image processing, complex calculations, or ML inference — use external services via the API Connector. Set up the external service's API in the API Connector (Plugins tab → API Connector → Add another API). Then in your Bubble workflow, call the external API as an action, send the data that needs processing, and receive the result. For example, send text to OpenAI's API for AI-powered content generation, or send an image URL to a processing service for resizing. The API Connector handles authentication and data mapping automatically.

> Pro tip: For complex external integrations that require multiple API calls, webhooks, or heavy data processing, RapidDev can help architect a solution that keeps your Bubble app responsive while offloading heavy work to optimized external services.

**Expected result:** Heavy processing is handled by external services, with results flowing back into your Bubble app via the API Connector.

## Complete code example

File: `Workflow summary`

```text
EXTENDING BUBBLE — METHODS SUMMARY
====================================

METHOD 1: HTML ELEMENT (Quick custom code)
  Design tab → + icon → HTML element
  Add <script> and <style> tags
  Scope: Single page only
  Use for: Small customizations, CSS overrides, simple interactions

METHOD 2: TOOLBOX PLUGIN (JS ↔ Bubble bridge)
  Install: Plugins tab → Search 'Toolbox' → Install
  JavaScript to Bubble element: Sends data from JS to Bubble
  Run javascript action: Executes JS from workflows
  Server script action: Runs JS in backend workflows
  Use for: When custom code needs to interact with Bubble data

METHOD 3: EXTERNAL LIBRARIES (Global scripts)
  Settings → SEO/metatags → Script/meta tags in header
  Add <script src='CDN_URL'></script>
  Available on all pages after load
  Use for: Charts, animations, formatting libraries

METHOD 4: CUSTOM PLUGIN (Reusable actions/elements)
  bubble.io/home/plugins → Create new plugin
  Define: Actions (JS functions), Elements (visual), API calls
  Install on your app to use in workflows
  Use for: Reusable custom functionality across pages/apps

METHOD 5: EXTERNAL API (Offload processing)
  Plugins tab → API Connector → Add API
  Configure auth, endpoints, parameters
  Call from workflows as plugin actions
  Use for: AI, image processing, complex calculations

DECISION GUIDE:
  One-time tweak → HTML element
  JS needs Bubble data → Toolbox plugin
  Reusable across pages → Custom plugin
  Heavy processing → External API
```

## Common mistakes

- **Adding multiple HTML elements with scripts on the same page** — Each HTML element renders independently. Multiple script elements can conflict with each other and increase page load time. Fix: Consolidate all scripts into a single HTML element. If scripts need to be separate, ensure they use unique variable names and do not conflict.
- **Loading large external libraries in the global header when only one page needs them** — Scripts in the global header load on every page, slowing down pages that do not use the library. Fix: Load page-specific libraries in an HTML element on that page instead of the global Settings header.
- **Storing sensitive API keys in JavaScript code within HTML elements** — JavaScript in HTML elements runs in the user's browser. Anyone can view the page source and extract API keys. Fix: Use the API Connector with Private parameters for any API key. Never put secrets in client-side JavaScript.

## Best practices

- Start with Bubble's built-in features and marketplace plugins before writing custom code
- Use the Toolbox plugin as the bridge between JavaScript and Bubble's visual logic
- Keep custom JavaScript minimal and focused on what Bubble cannot do natively
- Never expose API keys or secrets in client-side HTML elements
- Test custom plugins thoroughly in development before deploying to live
- Document any custom code in Notes (attached to the HTML element) so future developers understand it
- Use the API Connector for anything requiring server-side processing to keep credentials safe

## Frequently asked questions

### Is custom JavaScript allowed on Bubble's Free plan?

Yes. HTML elements with JavaScript work on all Bubble plans. The Toolbox plugin is also free. Custom plugins can be created and installed on any plan.

### Will custom JavaScript break when Bubble updates?

Custom JavaScript in HTML elements is isolated from Bubble's codebase, so it rarely breaks during updates. However, plugins that interact deeply with Bubble's internal APIs can break. Test after every major Bubble update.

### Can I use React or Vue inside a Bubble app?

Technically yes — you can load any library via a script tag. But Bubble already manages the DOM, so a full framework like React can cause conflicts. Use lightweight utility libraries instead of full frameworks.

### How do I debug custom JavaScript in Bubble?

Use your browser's Developer Tools (F12 or Cmd+Option+I). Open the Console tab to see JavaScript errors and the Elements tab to inspect your HTML element's output.

### Should I build a custom plugin or use an HTML element?

Use an HTML element for one-off customizations on a single page. Build a custom plugin if the functionality is needed on multiple pages or if you want to reuse it across different Bubble apps.

### Can RapidDev build custom Bubble plugins for my project?

Yes. RapidDev can design and build custom plugins that integrate with external services, add specialized UI components, or implement business logic that Bubble's visual editor cannot handle.

---

Source: https://www.rapidevelopers.com/bubble-tutorial/extend-bubble-custom-functionality
© RapidDev — https://www.rapidevelopers.com/bubble-tutorial/extend-bubble-custom-functionality
