Mobile Proxy for Bubble.io
Bubble's API Connector and backend workflow HTTP actions both originate from AWS — useless for any target that flags datacenter ASNs. The clean fix is a Cloudflare Worker relay that Bubble calls, which forwards through your mobile proxy slot.
Prerequisites
- →Bubble.io app on a paid plan (API Connector available on free tier, but backend workflows require a paid plan for production).
- →Cloudflare account with Workers enabled.
- →Mobile proxy slot + API key from mobileproxies.org.
Step-by-Step Configuration
Deploy the relay worker
Spin up a Node service on Fly.io / Railway / Render — Cloudflare Workers can't speak HTTP CONNECT to arbitrary hosts cleanly, so a small Node app is the most pragmatic relay:
// relay.js — Node 20+
import express from 'express';
import { fetch, ProxyAgent } from 'undici';
const app = express();
app.use(express.json({ limit: '2mb' }));
const PROXY = `http://${process.env.PROXY_USER}:${process.env.PROXY_PASS}@${process.env.PROXY_HOST}:${process.env.PROXY_PORT}`;
const agent = new ProxyAgent(PROXY);
app.post('/fetch', async (req, res) => {
if (req.headers['x-relay-key'] !== process.env.RELAY_KEY)
return res.status(403).send('forbidden');
const { url, method = 'GET', headers = {}, body } = req.body;
const r = await fetch(url, { method, headers, body, dispatcher: agent });
res.status(r.status);
for (const [k, v] of r.headers) res.setHeader(k, v);
res.send(Buffer.from(await r.arrayBuffer()));
});
app.listen(8080);Install the API Connector plugin in Bubble
In the Bubble editor: Plugins → Add plugins → API Connector. Create a new API named MobileProxyRelay.
Add a "Fetch via mobile proxy" API call
Inside the MobileProxyRelay API, click Add another call:
Name: fetch
Use as: Action # so backend workflows can call it
Data type: JSON
HTTP method: POST
URL: https://relay.your-domain.com/fetch
Headers:
Content-Type application/json
x-relay-key SHARED_SECRET # mark private
Body type: JSON
Body:
{
"url": "<target_url>",
"method": "<method>",
"headers": <headers_json>,
"body": "<body>"
}
Parameters: target_url, method, headers_json, body (all dynamic)Initialize the call
Click Initialize call with a sample target_url ofhttps://api.ipify.org. Bubble will display the response body — confirm it's a mobile IP before saving.
Use it from a backend workflow
Backend workflow: ScrapeCompetitor (custom event)
Inputs: competitor_url (text)
Step 1: MobileProxyRelay - fetch
target_url = competitor_url
method = "GET"
headers_json = {}
body = ""
Step 2: Create a new "ScrapeResult"
url = competitor_url
html = Result of step 1's body
status = Result of step 1's status_code
scraped_at = Current date/timeVerify It Works
Fire the backend workflow with competitor_url = https://api.ipify.org. Open the ScrapeResult database table and check the html field — should hold a single mobile-carrier IP string. If you see Bubble's AWS range, the API Connector is calling the target directly because the relay URL is wrong.
Scheduled IP Rotation
Add a second API call rotate that hits our switch endpoint directly (no proxy needed):
Name: rotate Use as: Action HTTP method: POST URL: https://buy.mobileproxies.org/api/v1/proxies/us-mob-01/switch Headers: Authorization Bearer YOUR_API_KEY Schedule via "API Workflow on a list" + "Schedule API workflow" every 1h.
Common Errors
"This data didn't match the structure of the initialized call"
Bubble locks the response schema at initialization. If the relay returns binary or HTML, switch the call's data type to Text instead of JSON and re-initialize.
Timeouts on backend workflows
Bubble caps API calls at 60 seconds. Use the relay's async mode: queue the job, return immediately, then store the result back into Bubble via the Data API webhook.
"403 forbidden" from relay
Bubble strips custom headers from non-private calls. Mark x-relay-key as private in API Connector — only then is it sent server-side.
Related Guides
Bubble Apps With Carrier-Grade Egress
$5 trial. Real carrier IPs reachable from any Bubble.io backend workflow via the relay pattern.