Connect Bubble to Mailchimp by adding the API Connector, setting the data-center-prefixed base URL (e.g., https://us14.api.mailchimp.com/3.0) — the single most common beginner mistake — and configuring HTTP Basic Auth with 'anystring' as the username and your API key as the password marked Private. Use PUT to add or update subscribers without 'Member Exists' errors, and wire the action to your Bubble landing page form submit workflow.
| Fact | Value |
|---|---|
| Tool | Mailchimp |
| Category | Marketing |
| Method | Bubble API Connector |
| Difficulty | Beginner |
| Time required | 30–45 minutes |
| Last updated | July 2026 |
The Data Center URL: Why Every First Mailchimp Integration in Bubble Fails
There is one gotcha in Mailchimp's API that breaks every beginner's first attempt, and it has nothing to do with authentication or permissions. It's the base URL.
Mailchimp API keys end with a data center suffix, like `-us14` or `-us8`. This suffix tells you which of Mailchimp's regional server clusters your account lives on. The API base URL must include that suffix as a subdomain: `https://us14.api.mailchimp.com/3.0`. If you use the generic URL `https://api.mailchimp.com/3.0`, every single API call returns a 404 error — not a 401 (auth error), a 404 — which makes the problem hard to diagnose.
Once you have the right base URL, the rest of the integration is clean. Bubble handles Mailchimp's Basic Auth (username = 'anystring', password = API key) natively in the API Connector's authentication dropdown — no header engineering needed. The API key stays server-side as a Private field. CORS is not an issue because Bubble proxies all API Connector calls from its servers.
The most common Bubble-Mailchimp use case is landing page opt-in: a visitor fills out a name and email form, clicks Submit, Bubble fires a workflow, and the subscriber is added to a Mailchimp audience instantly. Mailchimp handles double opt-in, unsubscribe management, and GDPR compliance from there. You can also read audience stats — subscriber counts, open rates, click rates — back into Bubble admin pages for monitoring without logging into Mailchimp.
Integration method
Bubble's API Connector handles Mailchimp's Basic Auth natively — username 'anystring', password = your API key marked Private. All calls run server-side with no CORS issues and no proxy functions needed.
Prerequisites
- A Bubble account on any plan (API Connector works on all plans including Free)
- A Mailchimp account — free tier allows up to 500 contacts and 1,000 emails/month
- A Mailchimp API key — generate at Account → Extras → API Keys → Create A Key
- Your Mailchimp data center code — found at the end of your API key (e.g., the key ends in '-us14', so your data center is 'us14')
- The Audience ID (List ID) of the Mailchimp audience you want to add subscribers to — found in Mailchimp under Audience → All contacts → Settings → Audience name and defaults → Audience ID
Step-by-step guide
Find Your Data Center Code and Gather Mailchimp Credentials
Before opening Bubble, collect the two pieces of information you need from Mailchimp: your API key and your Audience ID. Log in to Mailchimp and navigate to Account → Extras → API Keys. Click 'Create A Key' and give it a name like 'Bubble Integration'. Copy the generated key — it looks like `4a2f8c...xxxxxx-us14`. The data center suffix is everything after the last dash: in this example, `us14`. Write down this suffix separately. You'll use it to build your API base URL: `https://us14.api.mailchimp.com/3.0` (replace `us14` with your actual suffix). This is not a setting you enter once globally — it must be in the base URL field of your API Connector configuration. Next, get your Audience ID. Go to Audience → All contacts → Settings → Audience name and defaults. Scroll down to find the 'Audience ID' field (also called List ID in older Mailchimp docs). Copy it — it looks like `abc12345`. You'll need this in every API call that targets subscribers. Store both values somewhere handy (a notes file, not a Bubble text element). The API key should never appear in your Bubble app's visible content.
Pro tip: If you have multiple Mailchimp audiences (lists), each has a different Audience ID. The base URL is the same for all of them — only the list ID in the API path changes per call.
Expected result: You have your Mailchimp API key, your data center code (e.g., us14), and your Audience ID. You know your base URL will be https://{your-dc}.api.mailchimp.com/3.0.
Install the API Connector and Configure Mailchimp Authentication
Open your Bubble editor and go to Plugins → Add plugins. Search for 'API Connector' and install it (by Bubble, free). In the API Connector, click 'Add another API'. Name it 'Mailchimp'. In the Base URL field, enter your data-center-prefixed URL: `https://us14.api.mailchimp.com/3.0` — replacing `us14` with your actual data center code. This is the most important field in the entire configuration. If you enter `https://api.mailchimp.com/3.0` here (without the data center prefix), every API call will return a 404 error. For Authentication, click the dropdown and select 'HTTP Basic Auth'. Two fields appear: Username and Password. - Username: enter `anystring` (this is literal — any non-empty string works; Mailchimp does not validate the username, only the password) - Password: enter your full Mailchimp API key (the entire string including the data center suffix at the end) - Check the 'Private' checkbox next to the Password field — this keeps your API key server-side Do not add the Content-Type header as a shared header here — you'll add it at the individual call level where needed for POST and PUT calls. Click 'Save'.
1{2 "base_url": "https://us14.api.mailchimp.com/3.0",3 "authentication": {4 "type": "HTTP Basic Auth",5 "username": "anystring",6 "password": "<private: your_mailchimp_api_key>"7 }8}Pro tip: Double-check your data center code right now by copying the last 4-5 characters of your API key after the final dash. If the key ends in '-us8', your base URL is https://us8.api.mailchimp.com/3.0. The most common mistake is using the wrong data center number.
Expected result: The Mailchimp API appears in your API Connector list with the data-center-prefixed base URL and HTTP Basic Auth configured with a Private password. Ready to add API calls.
Create the Add or Update Subscriber Call Using PUT
Click 'Add a new call' under your Mailchimp API. Name it 'Add or Update Subscriber'. Set method to PUT. Set the path to `/lists/<dynamic: list_id>/members/<dynamic: subscriber_hash>`. The `subscriber_hash` is the MD5 hash of the subscriber's lowercase email address — this is how Mailchimp identifies subscribers in the PUT endpoint. Here is the important architectural decision: Bubble does not have a native MD5 function. You have two options: **Option A (Recommended for simplicity): Use POST instead of PUT.** Create a POST call to `/lists/<dynamic: list_id>/members`. POST creates a new subscriber but returns a 400 'Member Exists' error if the email is already in the list. For a simple opt-in form where you only add new subscribers, catch and ignore this 400 error using Bubble's 'Only when' condition or by not showing an error on 400 responses. **Option B: Use PUT with MD5 hash.** You need to compute the MD5 hash of the lowercase email before calling the API. One approach: use a third-party MD5 API call (there are free public MD5 hash endpoints) as a prior step in the workflow. Another: install the Toolbox plugin (by Zeroqode) which provides a 'Run JavaScript' action — you can use JavaScript's built-in crypto.subtle API to compute the hash. PUT is more powerful — it creates if not exists and updates if exists. For most beginners, Option A (POST with 400 error handling) is the right starting point. Add the PUT pattern later if you need to update existing subscribers. In either case, set Body type to JSON. The request body is shown in the code block. Add `Content-Type: application/json` as a call-level header. Change 'Use as' to 'Action'. Click 'Initialize call'. Enter a test email and your Audience ID as the list_id. For Option A (POST), if the email already exists you'll get a 400 which blocks initialization — use a fresh test email you've never added. Confirm a 200 response and the subscriber appears in your Mailchimp audience.
1{2 "POST method body (new subscribers only)": {3 "email_address": "<dynamic: email>",4 "status": "subscribed",5 "merge_fields": {6 "FNAME": "<dynamic: first_name>",7 "LNAME": "<dynamic: last_name>"8 },9 "tags": ["<dynamic: tag_name>"]10 },11 "PUT method body (create or update)": {12 "email_address": "<dynamic: email>",13 "status": "subscribed",14 "status_if_new": "subscribed",15 "merge_fields": {16 "FNAME": "<dynamic: first_name>",17 "LNAME": "<dynamic: last_name>"18 }19 }20}Pro tip: The 'status' field controls the opt-in type: 'subscribed' = direct opt-in (no confirmation email), 'pending' = double opt-in (Mailchimp sends a confirmation email the subscriber must click). For GDPR-compliant markets, use 'pending'. For US audiences where you have clear consent, 'subscribed' is simpler.
Expected result: The 'Add or Update Subscriber' call is initialized with a 200 response. The test email appears in your Mailchimp audience under Audience → All contacts. The call shows in the API Connector with a green checkmark.
Wire the Subscriber Add Action to a Form Submit Workflow
Now connect the API call to your Bubble landing page form. Navigate to the Workflow tab. Click on the form submit button element to create a workflow event, or use 'When Sign Up button is clicked'. Add a step in the workflow. Select 'Plugins → Mailchimp → Add or Update Subscriber'. Bubble shows input fields for each dynamic parameter you defined: - `list_id`: enter your Audience ID directly as a static value (e.g., `abc12345`) — this is the same for every call - `email`: map to 'Input Email's value' (or whatever your email input element is named) - `first_name`: map to 'Input First Name's value' - `last_name`: map to 'Input Last Name's value' - `tag_name`: enter a static value like `landing-page-signup` or leave blank if not using tags Add a second workflow step to give the user feedback: change the Submit button text to 'Subscribed! ✓' using 'Element Actions → Set state' or navigate to a confirmation page. Add an 'Only when' condition on the API call step if you want to validate the email input first: 'Only when Email input's value contains @'. This prevents obviously invalid emails from hitting the Mailchimp API. RapidDev's team has implemented Mailchimp subscriber sync for many Bubble landing page projects — if you need more complex segmentation logic (different audiences per landing page, tag-based automation triggers), a free scoping call is available at rapidevelopers.com/contact.
Pro tip: Add a Bubble Privacy rule on your User data type if you're also saving the email to a Bubble database table — ensure non-logged-in users (or users without the right role) cannot read other users' emails through Bubble's Data API.
Expected result: Filling out the form and clicking Submit in your Bubble preview triggers the workflow and adds the subscriber to Mailchimp within 1-2 seconds. The subscriber appears in Mailchimp's All contacts list with the correct status.
Create a Read Call for Audience Stats and Campaign Performance
Now add a read call so you can display Mailchimp data back in Bubble — useful for an admin dashboard or a subscriber count widget on your public page. Add a new call under Mailchimp. Name it 'Get Audience Stats'. Method = GET. Path = `/lists/<dynamic: list_id>`. Use as = Data. No body needed. Initialize the call with your Audience ID. Bubble detects the response fields including `stats > member_count`, `stats > open_rate`, `stats > click_rate`, and `name` (the audience name). On your admin page, add text elements mapped to: - Subscriber Count: `Current call's stats member_count` (shown as a number) - Open Rate: `Current call's stats open_rate * 100` formatted with 2 decimal places and a % suffix - Click Rate: `Current call's stats click_rate * 100` formatted similarly Note: Mailchimp returns open_rate and click_rate as decimals (0.245 = 24.5%). Always multiply by 100 before displaying as a percentage. The raw decimal value looks like terrible performance if not converted. For campaign-level stats, add a second GET call: `/campaigns?list_id=<dynamic>&count=1&sort_field=send_time&sort_dir=DESC`. This returns your most recent campaign with its report_summary data (opens, clicks, unsubscribes). Initialize and map to your admin page.
1{2 "method": "GET",3 "url": "https://us14.api.mailchimp.com/3.0/lists/<dynamic: list_id>",4 "authentication": "HTTP Basic Auth (anystring / <private: api_key>)",5 "example_response_stats": {6 "stats": {7 "member_count": 1247,8 "open_rate": 0.2458,9 "click_rate": 0.0812,10 "campaign_count": 3411 },12 "name": "My Newsletter Audience"13 },14 "bubble_formula_open_rate": "Current call's stats open_rate * 100"15}Pro tip: For a public-facing subscriber count widget ('Join 1,247 subscribers!'), use the get audience stats call data source on your landing page — set the list_id as a static parameter. No user authentication required for this display.
Expected result: The admin page displays real-time Mailchimp subscriber count, open rate, and click rate data. The numbers update automatically on page load from the live Mailchimp API.
Common use cases
Landing Page Newsletter Opt-In
The classic Bubble + Mailchimp pattern: a landing page with a name and email input, a Submit button that triggers a Bubble workflow, and a Mailchimp API Connector call that adds the subscriber to an audience. Use PUT to handle both new subscribers and returning subscribers who previously unsubscribed — without POST's 'Member Exists' error.
On the Subscribe button click workflow: Step 1 - Call Mailchimp API 'Add or Update Subscriber' with email = Email input's value, first_name = Name input's value, status = 'subscribed'. Step 2 - Show a success message 'Thanks! You're subscribed.' Step 3 - Clear the input fields.
Copy this prompt to try it in Bubble
Audience Stats Dashboard
Build a lightweight admin page in Bubble that shows your Mailchimp audience health: total subscriber count, open rate, click rate, and unsubscribe rate for the last campaign sent. Map GET /lists/{listId} and GET /campaigns data to text elements on the admin page so your team can check email performance without Mailchimp credentials.
Add text elements on Admin page: Subscriber Count = result of 'Get Audience Stats' API call's stats > member_count. Open Rate = result of 'Get Last Campaign' API call's report_summary > open_rate * 100 formatted as percentage. Last Updated = Now formatted as date.
Copy this prompt to try it in Bubble
Tag-Based Subscriber Segmentation
When users complete specific actions in your Bubble app (completed a course, made a purchase, reached a milestone), add a Mailchimp tag to their subscriber profile via the Tags API. Mailchimp can then automatically trigger tag-based email sequences — course completion follow-ups, upsell campaigns — without manual segment management.
In the 'Course Completed' workflow: after updating the course completion record, call Mailchimp API 'Add Subscriber Tag' with email = Current User's email, tag_name = 'course-completed-module-1'. This triggers the Mailchimp automation sequence for that tag segment.
Copy this prompt to try it in Bubble
Troubleshooting
Every API call returns a 404 error even with correct authentication
Cause: The base URL in the API Connector is missing the data center prefix. Using https://api.mailchimp.com/3.0 instead of https://us14.api.mailchimp.com/3.0 (with your actual data center code) causes 404 on every call because the generic URL doesn't route to your account's server cluster.
Solution: Check your API key — the data center code is everything after the last dash (e.g., -us14 means data center is us14). Update the base URL in Bubble's API Connector to https://{your-dc}.api.mailchimp.com/3.0. Save the configuration and re-initialize the call.
POST to /lists/{listId}/members returns a 400 'Member Exists' error
Cause: The email address is already a member of this Mailchimp audience. POST /members does not perform upserts — it fails if the subscriber already exists.
Solution: Switch from POST to PUT /lists/{listId}/members/{subscriber_hash} which performs an upsert (creates if new, updates if exists). For the PUT method, compute the subscriber hash (MD5 of lowercase email). Alternatively, if you're using POST intentionally, add a Bubble workflow condition to catch and ignore 400 responses — or display a friendly message like 'You're already subscribed!'
Bubble's 'Initialize call' fails or times out before I can save the API call
Cause: The Initialize call requires a real successful API response. If the API key, base URL, or request body has errors, initialization fails and Bubble cannot detect response fields. A common cause is using a placeholder email during initialization instead of a real address.
Solution: Use a real email address you own and have never added to this Mailchimp audience during initialization. Ensure the base URL includes the data center prefix. After successful initialization, the email will be added to your Mailchimp audience — remove it manually if you don't want the test address in your list.
Open rate and click rate values display as very small decimals (0.245) instead of percentages
Cause: Mailchimp returns rate metrics as decimal fractions (0.245 = 24.5%), not as percentages. Displaying the raw value without conversion shows 0.24 instead of 24%.
Solution: In Bubble's text element formula for open/click rates, multiply the API value by 100: 'Current call's stats open_rate * 100'. Format the result with 2 decimal places and append a % symbol or percentage text element.
Bulk contacts added via the marketing contacts import API show a job ID but no immediate confirmation
Cause: Mailchimp's batch import endpoint (POST /v3/lists/{listId}/members/batch or the bulk contacts API) is asynchronous. It returns a job_id immediately but processes contacts in the background — they may not appear in the audience for several minutes.
Solution: This is expected behavior for batch imports. For single-subscriber opt-ins (PUT/POST per individual), the response is synchronous and the subscriber appears immediately. For bulk imports, poll the import status endpoint with the job_id to check when processing is complete, or simply wait and verify in Mailchimp's All contacts view after a few minutes.
Best practices
- Always include the data center code in the Mailchimp base URL — triple-check this before any other configuration step. Without it, every call returns 404.
- Mark the API key (Basic Auth password field) as Private in Bubble's API Connector to ensure it stays server-side.
- Use PUT /lists/{listId}/members/{hash} over POST /lists/{listId}/members when you expect returning subscribers — PUT upserts without the 'Member Exists' 400 error.
- Multiply open_rate and click_rate values by 100 in all Bubble display formulas — Mailchimp returns these as decimals, not percentages.
- Add double opt-in (status = 'pending') for EU audiences to comply with GDPR — Mailchimp handles the confirmation email flow automatically when status is 'pending'.
- Store the Audience ID (list_id) in a Bubble App Data config record rather than hardcoding it in every API call — this makes switching audiences or adding new ones easier.
- WU awareness: each form submission that calls the Mailchimp API consumes Workload Units. For high-traffic landing pages with many opt-ins, monitor WU usage in the Logs tab and ensure your Bubble plan's WU allocation is sufficient.
- Set up a simple Mailchimp automation (welcome email sequence) in Mailchimp's own Automations feature for post-opt-in engagement — this requires no extra Bubble API calls and runs entirely within Mailchimp.
Alternatives
SendGrid is for transactional email — one email per user action triggered from Bubble workflows. Mailchimp is for campaign email — managing subscriber lists and sending newsletters to segments. For welcome emails and order confirmations, use SendGrid. For newsletters and drip campaigns, use Mailchimp. Many Bubble apps use both.
Klaviyo combines list management and transactional email with behavioral segmentation tied to purchase events. It's more powerful than Mailchimp for e-commerce Bubble apps but costs more and has a more complex API (requires a revision header, uses JSON:API response format). For simple newsletter opt-ins, Mailchimp is easier.
HubSpot handles email marketing plus CRM contact management, deal tracking, and sales pipeline. If you need to manage leads and contacts as well as send emails, HubSpot combines both. For simple newsletter opt-ins with no CRM need, Mailchimp is simpler and cheaper.
Frequently asked questions
Why does Mailchimp use 'anystring' as the Basic Auth username?
Mailchimp's API documentation specifies that the username in Basic Auth can be any non-empty string — the API only validates the password field (your API key). This is a quirk of Mailchimp's authentication design. The literal string 'anystring' is the conventional placeholder most tutorials use, though 'user', 'bubble', or any other text works equally well.
What is the data center code and where do I find it?
The data center code is the suffix at the end of your Mailchimp API key, after the last dash. For example, if your API key ends in '-us14', your data center is 'us14' and your base URL is https://us14.api.mailchimp.com/3.0. Each Mailchimp account is assigned to a specific data center when created. The correct suffix is always in your API key.
Do I need a paid Bubble plan to use the Mailchimp integration?
No. The API Connector plugin works on all Bubble plans including the free plan. Both the subscriber add call (triggered by a button click) and the audience stats read call work without Backend Workflows. You only need a paid Bubble plan if you want to trigger Mailchimp calls from Backend Workflows (scheduled sends, server-side events).
How do I handle the case where someone submits the form with an email that's already in my list?
There are two approaches. Option 1: Use PUT instead of POST — PUT performs an upsert and doesn't error on existing subscribers (though it requires the MD5 subscriber hash). Option 2: Use POST and add an 'Only when' condition or error handler that treats a 400 response as a non-blocking outcome, showing the user a message like 'You're already subscribed — thanks!' Either approach works for a landing page opt-in flow.
Can I add subscribers to multiple Mailchimp audiences from Bubble?
Yes. The list_id parameter in the API call path is dynamic, so you can pass different Audience IDs to the same API Connector call. Create a Bubble workflow that calls the 'Add or Update Subscriber' action multiple times with different list_id values, or use different API calls with hardcoded list_ids for clarity.
Is there a Mailchimp plugin for Bubble I should use instead of the API Connector?
There are community-built Mailchimp plugins on the Bubble marketplace, but they vary in quality and maintenance. The API Connector approach gives you full control over which endpoints you call, how errors are handled, and which fields are marked Private. For a production app, building the integration yourself with the API Connector is more reliable than depending on a third-party plugin that may not be maintained.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation