Chrome extension iframing and making API calls to a Bubble app

I’m working on an idea that involves a Chrome extension. The extension does a couple of things:

  1. When you click on its icon in Chrome’s extension strip (to the right of the URL bar), it’ll open a small popup that iframes a Bubble app. In the iframed interface, the user will be able to log into the Bubble app and engage with certain pages
  2. The extension has a script that runs in the background that, when triggered, will make API calls to the same Bubble app as above, mainly via API Workflows

The API Workflows that I want to call have to be protected by authentication.

My question is: any advice on how to get this all set up on the authentication front? I’m wondering if it’s possible that an end user logging into the iframed app actually creates a token that the extension can save to make its API calls - e.g. does the cookie a Bubble app creates actually also serve as a token for API calls? I would prefer not to require the end-user to log into the iframed app for #1, then go through another OAuth flow to enable #2.

I figured out how to get it to work, so posting some solutions here in case it helps others in the future!

All of this is with Chrome extension manifest v3, since Chrome is deprecating v2.

To iframe a Bubble app into a popup upon clicking the extension icon

If a user has an extension installed, it’ll show up in the ‘extension strip’ that’s to the right of the URL bar. You can make it so that when the user clicks on the extension’s icon, a popup appears, anchored to the icon, that loads whatever HTML/CSS/JS you want - it can also load an iframed Bubble app.

At its most basic, you need something like:

manifest.json
Notably here, you’re using the “action” capability to signify you want to open the file “popup.html” as a popup upon click

{
    "name": "Blah",
    "description": "Lorem ipsum",
    "version": "0.1",
    "manifest_version": 3,
    "action": {
        "default_popup": "popup.html"
    },
   ...
}

popup.html
Notably here, there’s a div that’s for the iframe, and otherwise the HTML just invokes popup.js

<!DOCTYPE html>
<html>
<head>
    <link rel="stylesheet" href="popup.css">
</head>
<body>
    <script src="popup.js"></script>
    <div id="iframe_div">
        <div class="lds-ring">
            <div></div>
            <div></div>
            <div></div>
            <div></div>
        </div>
    </div>

</body>
</html>

popup.js
Notably, this does the actual loading of the iframe

let iframe;
let iframe_url = "bubble.io";  // This is the URL of what you want to iframe - this URL will load when the popup first opens
let width = 360;
let height = 400;

let iframe_onload = function () {
    // This function fires when the iframe is finished loading

    // Remove loading spinner
    let loading = document.getElementsByClassName('lds-ring')[0];
    if (loading) {
        loading.remove();
    }
}


window.onload = function () {
    // Load iframe    
    setTimeout(function () {
        let group = document.getElementById("iframe_div");
        let i = document.createElement('iframe');
        i.frameBorder = 0;
        i.width = width;
        i.height = height;
        i.src = iframe_url;
        i.onload = iframe_onload;
        iframe = group.appendChild(i);
    }, 100);
    ...
}

Communicating with the Bubble app in the iframe

This is where things get a bit annoying - when a website is running within an iframe, there are restrictions around how you can communicate with it.

Running code when the iframe loads a particular page

Sometimes, you may want the Chrome extension to run some arbitrary code when it detects that the user has navigated to a certain page of your Bubble app within the iframe. To do that, add this to popup.js:

window.addEventListener("message", (event) => {

        const iframeUrl = event.data;
        if (iframeUrl.includes("code=st_")) {
            // Arbitrary code here
        }
        ...
})

Getting the Bubble app’s page in the iframe to update

Say you want the code in the extension to make some kind of change on a page in the Bubble app that’s iframed. For example, maybe you want the Bubble app page to reflect a success / fail status based on logic in the code.

To do this, you need a content script - this is code that runs from the extension when the browser detects you’re on a certain URL.

First, add this to manifest.json, to load the content script on the right page(s):

...
"content_scripts": [
    {
        "matches": ["https://your.bubbleapp.url.here.io/*"],
        "js": ["bubble-content-script.js"],
        "all_frames": true
    }
    ],
...

The way we’ll make this work is to inject code into the iframed Bubble app that opens a ‘connection’ that can pass messages to the rest of the Chrome extension code.

In bubble-content-script.js, you have this:

let port = chrome.runtime.connect({name: 'test'});
port.onMessage.addListener((msg, port) => {
    if (msg.type == 'arbitrary-message-code-word-here') {
        // Change HTML element on the Bubble app page to reflect success
        document.getElementById('some_element_id').innerHTML = 'Success';
        // Hide another element
        document.getElementById('another_element_id').style.display = "none";
    } else if (msg.type == 'a-different-message-code-word') {
        ...
    }
});

Then in another extension code file, like popup.js, you can do something like this to send the iframed page a message:

window.onload = function () {

    // Establish connection with Bubble app page's content script
    let iframePort; // Can be used later in this function
    chrome.runtime.onConnect.addListener(port => {
        iframePort = port;
        port.onMessage.addListener((msg, port) => {
            console.log(msg);
        });
        port.postMessage('from-popup');
    });

    ...
    // Later on
    iframePort.postMessage('arbitrary-message-code-word-here')
}

i created a free crash course on the topic: Bubble Chrome Extension Crash Course

This topic was automatically closed after 70 days. New replies are no longer allowed.