# ConvertKit

- Tool: Bubble
- Difficulty: Beginner
- Time required: 1–2 hours
- Last updated: July 2026

## TL;DR

Connect Bubble to ConvertKit (now Kit) using the API Connector plugin with the api_secret as a Private Shared Parameter — not a header. Bubble appends it server-side to every request so it never reaches the browser. Unlike OAuth-based email tools, ConvertKit's api_secret never expires, making this a maintenance-free setup. The free ConvertKit plan (up to 10,000 subscribers) includes API access.

## Add ConvertKit subscriber management directly into your Bubble app

ConvertKit — now officially rebranded as Kit — is the email platform of choice for creators and indie founders building online businesses. Its API v3 lives at https://api.convertkit.com/v3 and uses a notably simple authentication model: a query parameter called api_secret that you append to every request. No OAuth dance, no expiring tokens, no refresh logic. Once configured, it works indefinitely.

The primary Bubble use case is building a subscriber-management panel or wiring ConvertKit opt-ins directly into your Bubble signup flow, product checkout, or content unlock workflow. Instead of embedding ConvertKit's HTML form widget, you can call the API directly from a Bubble Workflow — giving you full control over the subscriber data, the form styling, and the post-subscribe experience inside your Bubble app.

One nuance to understand upfront: ConvertKit has two API credentials. The api_key is a read-only public key used for embedding forms and fetching public data. The api_secret is the full-access credential required for all write operations (subscribing, tagging, adding to sequences). Make sure you are using the api_secret for the Private Shared Parameter in the API Connector, not the api_key.

## Before you start

- A ConvertKit (Kit) account — the free plan includes API access for up to 10,000 subscribers
- Your ConvertKit API Secret from Settings → Advanced (not the public API Key)
- The Form ID for the ConvertKit form(s) you want to subscribe users to (visible in the form URL in the ConvertKit dashboard)
- A Bubble account with the API Connector plugin installed (free, by Bubble)

## Step-by-step guide

### 1. Retrieve your ConvertKit API Secret and Form IDs

Log in to your ConvertKit (Kit) account and navigate to Settings → Advanced. You will see two API credentials:
- API Key: a shorter string starting with letters — this is read-only and used for public-facing embed scripts
- API Secret: a longer alphanumeric string — this is the full-access credential you need for all write operations

Copy the API Secret and store it securely. Do not confuse the two. Using the API Key for write operations (subscribing, tagging) will silently fail or return 401 errors.

Next, find the Form IDs for any ConvertKit forms you plan to subscribe users to. In ConvertKit, go to Landing Pages & Forms. Click on a form to open it. Look at the URL in your browser — it follows the pattern: app.convertkit.com/forms/[FORM_ID]/edit. The number in that URL is your Form ID. Hardcode these as Bubble App Constants later — they do not change unless you delete and recreate the form.

Note: ConvertKit completed a rebrand to 'Kit' in 2024, but the API domain, endpoints, and documentation still reference 'convertkit' — api.convertkit.com and app.convertkit.com. Both brand names refer to the same product and the same API.

**Expected result:** You have the API Secret copied, and a list of Form IDs and Sequence IDs from the ConvertKit dashboard URL paths.

### 2. Configure the API Connector with a Private Shared Parameter

In your Bubble app editor, click the Plugins tab, then 'Add plugins'. Search for 'API Connector' (the free plugin by Bubble) and install it. Click on the API Connector in your plugins list, then click 'Add another API'. Name this API 'ConvertKit'.

Set the Base URL to: https://api.convertkit.com/v3

Here is the key difference from most API integrations: ConvertKit's authentication is a query parameter, not a header. Click 'Add a shared parameter' (below the headers section). Set the Key to: api_secret. Set the Value to your ConvertKit API Secret. Check the 'Private' checkbox next to this parameter.

This Private Shared Parameter will be automatically appended to every API call URL you create under this API. Bubble sends it from its servers, so it never appears in browser network traffic or page source. Do not add it to individual calls — the shared parameter handles it globally.

Leave the Content-Type header configuration blank for now — the API Connector will set this automatically based on the call method when you add individual calls.

```
{
  "api_name": "ConvertKit",
  "base_url": "https://api.convertkit.com/v3",
  "shared_parameters": [
    {
      "key": "api_secret",
      "value": "YOUR_API_SECRET_HERE",
      "private": true
    }
  ]
}
```

**Expected result:** The API Connector lists 'ConvertKit' with a Private api_secret shared parameter. The api_secret will be appended as ?api_secret=xxx to every call made under this API.

### 3. Add subscribe and list API calls

Under your ConvertKit API in the API Connector, add these calls:

Call 1 — 'subscribe_to_form': POST /forms/[form_id]/subscribe
In the URL path, add '/forms/[form_id]/subscribe' — the [form_id] portion should be set as a dynamic parameter. Add two body parameters: 'email' and 'first_name' — both non-private, as these will be supplied from Bubble data at call time. Set 'Use as' to Action (since this is a POST that triggers a subscription, not a data retrieval). Set the Content-Type to 'application/json'. For initialization, enter a test form_id (use a real ConvertKit form ID from your account), test email (use your own), and a test first_name, then click 'Initialize call'.

Call 2 — 'get_subscribers': GET /subscribers
Set 'Use as' to Data. Add optional query parameters: 'email_address' (non-private, for filtered lookups). Initialize against your account — it should return your existing subscriber list.

Call 3 — 'subscribe_to_sequence': POST /sequences/[sequence_id]/subscribe
Same pattern as subscribe_to_form but for sequences. Add email and first_name body params, set Use as Action.

Call 4 — 'add_tag': POST /tags/[tag_id]/subscribe
Same pattern — email and first_name body params, Use as Action.

```
Call 1: POST https://api.convertkit.com/v3/forms/[form_id]/subscribe
Body (JSON):
  email: <dynamic>
  first_name: <dynamic>
Use as: Action

Call 2: GET https://api.convertkit.com/v3/subscribers
Query params:
  email_address: <dynamic, optional>
Use as: Data

Call 3: POST https://api.convertkit.com/v3/sequences/[sequence_id]/subscribe
Body (JSON):
  email: <dynamic>
  first_name: <dynamic>
Use as: Action

Call 4: POST https://api.convertkit.com/v3/tags/[tag_id]/subscribe
Body (JSON):
  email: <dynamic>
  first_name: <dynamic>
Use as: Action

Note: api_secret is automatically appended as a shared parameter — do not add it to individual calls.
```

**Expected result:** Four API calls are initialized and showing green in the API Connector: subscribe_to_form (Action), get_subscribers (Data), subscribe_to_sequence (Action), and add_tag (Action).

### 4. Store subscriber data in Bubble's User Data Type

When ConvertKit returns a subscriber object after a successful subscribe call, capture the ConvertKit subscriber ID and store it in the Bubble User record. This subscriber ID is essential for future API calls — applying tags, adding to sequences, looking up subscriber status — because the ConvertKit API accepts both email and subscriber ID as identifiers, but subscriber ID is more reliable for existing contacts.

In Bubble's Data tab, add these fields to the existing User Data Type (or create a new App User extension type if your app uses a separate profile):
- convertkit_id: Text (the ConvertKit subscriber ID returned on subscribe)
- convertkit_subscribed_at: Date
- convertkit_tags: Text (comma-separated list of applied tags, for local reference)

Also go to Data tab → Privacy for the User Data Type and verify these fields are not exposed to 'Everyone else' — subscriber IDs should be treated as semi-private identifiers.

In your subscribe Workflow, after the subscribe_to_form API call succeeds, add a 'Make changes to a thing' step targeting the current User, setting convertkit_id = Result of Step 1's subscriber's id and convertkit_subscribed_at = Current date/time.

```
User Data Type — additional fields:
  convertkit_id: Text
  convertkit_subscribed_at: Date
  convertkit_tags: Text

Workflow step after subscribe_to_form:
  Action: Make changes to Current User
    convertkit_id: Result of subscribe_to_form's subscriber's id
    convertkit_subscribed_at: Current date/time
```

**Expected result:** After a user subscribes through your Bubble form, their User record shows a convertkit_id field with a numeric value matching their ID in the ConvertKit dashboard.

### 5. Build the multi-step subscribe + tag + sequence workflow

The most powerful Bubble + ConvertKit pattern is a single user action that triggers three coordinated API calls: subscribe to a form, apply a tag, and add to a sequence. This is the typical onboarding flow for creator products.

In your Bubble Workflow editor, add steps to a button click or signup event:

Step 1: Call API → ConvertKit - subscribe_to_form
Parameters: form_id = App Constant CONVERTKIT_FORM_ID, email = Current User's email, first_name = Current User's first name

Step 2: Call API → ConvertKit - add_tag
Parameters: tag_id = App Constant CONVERTKIT_ONBOARDING_TAG_ID, email = Current User's email, first_name = Current User's first name

Step 3: Call API → ConvertKit - subscribe_to_sequence
Parameters: sequence_id = App Constant CONVERTKIT_WELCOME_SEQUENCE_ID, email = Current User's email, first_name = Current User's first name

Step 4: Make changes to Current User — convertkit_id = Result of Step 1's subscriber's id

Note: Adding a subscriber to a sequence does NOT automatically add them to the form — these are separate ConvertKit objects. If your Bubble flow requires both form and sequence membership (so the subscriber appears in form analytics AND receives sequence emails), both the subscribe_to_form and subscribe_to_sequence calls are necessary. RapidDev's team has built subscriber management flows like this for dozens of Bubble creator and SaaS apps — if you need help designing the tag taxonomy or sequence logic for your product, reach out at rapidevelopers.com/contact.

```
Workflow: Button 'Get Access' clicked (or User creation event)

Step 1: Call API → ConvertKit - subscribe_to_form
  form_id: App Constant 'CONVERTKIT_FORM_ID'
  email: Current User's email
  first_name: Current User's first name

Step 2: Call API → ConvertKit - add_tag
  tag_id: App Constant 'CONVERTKIT_ONBOARDING_TAG_ID'
  email: Current User's email
  first_name: Current User's first name

Step 3: Call API → ConvertKit - subscribe_to_sequence
  sequence_id: App Constant 'CONVERTKIT_WELCOME_SEQUENCE_ID'
  email: Current User's email
  first_name: Current User's first name

Step 4: Make changes to Current User
  convertkit_id: Result of Step 1's subscriber's id
  convertkit_subscribed_at: Current date/time
```

**Expected result:** A single user action triggers all three ConvertKit API calls in sequence. The user appears in ConvertKit with the correct form, tag, and sequence assignments. The Bubble User record is updated with the ConvertKit subscriber ID.

### 6. Add subscriber lookup for deduplication and status checking

Although ConvertKit silently upserts duplicate subscriptions (so double-subscribing is not destructive), understanding whether a subscriber is new or returning is valuable for analytics and conditional messaging. Use the get_subscribers call with the email_address filter to look up a subscriber before taking action.

In your Workflow, add a first step before the subscribe_to_form call:

Step 0: Call API → ConvertKit - get_subscribers
Parameter: email_address = Input's email value (or Current User's email)

After this call, add a Conditional: 'Only when Result of Step 0's total_subscribers is 0' on the subscribe_to_form step. This way, if a subscriber already exists, the form subscription is skipped (ConvertKit would upsert silently anyway, but now you have a flag to show different messaging to returning vs new subscribers).

You can also use the subscriber lookup to read a returning user's existing ConvertKit ID and store it in their Bubble User record if they sign in through a different path. The GET /subscribers?email_address=[email] endpoint returns the subscriber object including their ID, state (active, inactive, bounced, unsubscribed), created_at date, and current tags.

Bubble's API Connector will auto-detect the response shape during initialization — verify that the 'subscribers' array field and its nested fields (id, email_address, state, tags) are correctly typed. If not detected correctly, re-initialize using your own email address which you know has data.

```
Workflow with subscriber lookup:

Step 0: Call API → ConvertKit - get_subscribers
  email_address: InputEmailField's value
  Result name: lookup_result

Step 1 [Only when: lookup_result's total_subscribers = 0]:
  Call API → ConvertKit - subscribe_to_form
  (new subscriber only)

Step 2 [Only when: lookup_result's total_subscribers > 0]:
  Make changes to Current User
  convertkit_id: lookup_result's subscribers:first item's id
  (sync existing ConvertKit ID for returning user)

GET response shape:
{
  "total_subscribers": 1,
  "subscribers": [
    {
      "id": 123456789,
      "email_address": "user@example.com",
      "state": "active",
      "created_at": "2025-01-15T10:30:00Z",
      "tags": [
        {"id": 111, "name": "new-signup", "created_at": "..."}
      ]
    }
  ]
}
```

**Expected result:** The lookup step correctly identifies existing vs new subscribers. New subscribers are added to ConvertKit. Returning subscribers have their existing ConvertKit ID synced to their Bubble User record without triggering a duplicate subscription.

## Best practices

- Always use the api_secret (not the api_key) in the Private Shared Parameter for write operations. The api_key is read-only and will cause silent failures or 401 errors on subscribe, tag, and sequence calls.
- Store ConvertKit Form IDs, Tag IDs, and Sequence IDs as Bubble App Constants rather than hardcoding them in individual workflow steps. This makes updating your ConvertKit structure a one-line change rather than a workflow audit.
- Store the ConvertKit subscriber ID in the Bubble User Data Type after the first subscribe call. Future calls (applying tags, checking status, adding to sequences) can reference this ID for more reliable lookups than email-based queries.
- Add Conditional branching to handle unsubscribed and bounced subscriber states. If a GET /subscribers lookup returns state: 'unsubscribed', respect that preference and do not re-subscribe them without an explicit opt-in action.
- Use App Constants for all ConvertKit IDs so your product team can reconfigure the email integration without touching workflow logic. Document which App Constant corresponds to which ConvertKit form or sequence.
- Be aware that Bubble's API Connector consumes Workload Units (WU) for every call made. For high-traffic signup flows, consider batching subscriber additions in a Backend Workflow rather than one call per user event to reduce WU costs.
- Mention both names — ConvertKit and Kit — in your internal documentation. The API domain and endpoints still use 'convertkit' (api.convertkit.com) even after the Kit rebrand, which can cause confusion when new team members look up documentation.
- Set privacy rules on any Bubble Data Type that stores ConvertKit subscriber data. Email addresses and subscriber IDs are personally identifiable information — ensure 'Everyone else' cannot search or read these records in your Bubble Data tab → Privacy configuration.

## Use cases

### Bubble signup form that adds subscribers to ConvertKit

Replace ConvertKit's embedded HTML form widget with a native Bubble signup form. When a user submits the form, a Bubble Workflow calls the ConvertKit API to subscribe their email to the correct form, apply relevant tags, and add them to an onboarding sequence — all in one seamless flow with your Bubble app's own design.

Prompt example:

```
Build a Bubble signup page with an email and first name input. When the form is submitted, call the ConvertKit API to subscribe the user to form ID 12345, apply the tag 'new-signup', and add them to sequence ID 67890. Show a success message after all three steps complete.
```

### Purchase-triggered email sequence enrollment

When a user completes a purchase in your Bubble e-commerce or membership app, automatically add them to a ConvertKit post-purchase email sequence. Store the ConvertKit subscriber ID in their Bubble User record so future API calls (applying purchase-specific tags, checking subscription status) can target the correct subscriber.

Prompt example:

```
In my Bubble membership app, when a user's Payment record status changes to 'completed', trigger a Workflow that calls ConvertKit to add the user to the 'Customer Onboarding' sequence and apply a tag named after their purchased plan tier.
```

### Subscriber status dashboard for team management

Build an internal admin panel in Bubble that displays subscriber counts, lets team members look up any subscriber by email to see their tags and sequences, and provides one-click buttons to apply or remove tags — eliminating the need for every team member to log in to ConvertKit directly.

Prompt example:

```
Build an admin page in Bubble that lets me search for a ConvertKit subscriber by email using the API, displays their tags and sequence memberships, and has buttons to apply or remove specific tags without going to the ConvertKit dashboard.
```

## Troubleshooting

### Subscribe call returns 401 Unauthorized even though the API secret looks correct

Cause: The most common cause is using the api_key (the shorter read-only credential) instead of the api_secret (the full-access credential). Both are visible in ConvertKit Settings → Advanced, and they look similar — but only api_secret allows write operations.

Solution: Log in to app.convertkit.com, go to Settings → Advanced, and compare the two credentials. The api_key is shorter and labeled 'API Key'. The api_secret is longer and labeled 'API Secret'. Copy the API Secret and update the value in the Shared Parameter in your API Connector configuration. Re-initialize the subscribe call to confirm it succeeds.

### Initialize call fails with 'There was an issue setting up your call' for the subscribe_to_form endpoint

Cause: The Form ID used during initialization does not exist in your ConvertKit account, or the email used for the test subscription is already unsubscribed/bounced and ConvertKit returns an error state.

Solution: Verify the Form ID from your ConvertKit dashboard URL (app.convertkit.com/forms/[FORM_ID]/edit). Use your own email address (which you know is in a valid state) for the initialization test subscription. If ConvertKit returns a specific error in the Bubble Logs tab → API Connector section, read the error message body — it usually specifies whether the issue is an invalid form ID or a subscriber state problem.

### Subscribers added from Bubble do not appear in ConvertKit form analytics

Cause: Subscribing via the API adds users to your ConvertKit account but may not attribute them to a specific form in analytics if the form_id parameter is missing or incorrect. Adding to a sequence separately does not create a form association.

Solution: Confirm you are calling POST /forms/[form_id]/subscribe with the correct form_id (not just the sequence subscribe endpoint). Each form subscription creates a separate attribution record in ConvertKit's analytics. Check the ConvertKit Subscribers tab and filter by the specific form to verify new subscribers are being attributed correctly.

### Workflow triggers multiple API calls and hits rate limits unexpectedly

Cause: ConvertKit's rate limit is not publicly documented but is approximately 1 request per second for write operations. If a Bubble Workflow triggers subscribe, tag, and sequence calls in parallel or in very rapid succession for many users simultaneously (e.g., a batch import), the API may start throttling.

Solution: Structure multi-step workflows so subscribe, tag, and sequence calls run sequentially (Steps 1, 2, 3) rather than in parallel. For bulk subscriber imports, use a recursive Backend Workflow with a delay between iterations. Monitor Bubble's Logs tab → API Connector logs for 429 rate limit responses and add additional delays if they appear.

## Frequently asked questions

### Is ConvertKit free to use with the Bubble API Connector?

Yes — ConvertKit's free plan includes API access for up to 10,000 subscribers. You do not need a paid ConvertKit plan to start building with the API. Paid plans (Creator $25/mo, Creator Pro $50/mo) add features like advanced reporting and automations, but the API itself works on the free tier.

### What is the difference between ConvertKit's api_key and api_secret?

ConvertKit provides two credentials: the api_key is a read-only public key used for embedding forms and reading public subscriber counts. The api_secret is a full-access credential required for all write operations — subscribing users, applying tags, adding to sequences. In Bubble's API Connector, you need the api_secret in the Private Shared Parameter. Using api_key for write operations will return 401 errors.

### What is ConvertKit Kit — is it a different product?

ConvertKit rebranded to Kit in 2024 but the underlying product and API are identical. The API domain remains api.convertkit.com, all endpoints use 'convertkit' paths, and the documentation at developers.convertkit.com still references the original name. The rebrand is cosmetic — your existing API credentials, form IDs, and integration logic continue to work unchanged.

### Will Bubble users be able to see my ConvertKit API secret?

No. When you place the api_secret in a Shared Parameter with the Private checkbox enabled in the API Connector, Bubble stores and sends it from its servers only. It never appears in client-side JavaScript, browser network logs, or page source. Bubble proxies all API Connector calls through its own infrastructure, keeping Private parameters completely hidden from end users.

### Do I need a paid Bubble plan to use the ConvertKit API integration?

No. The API Connector for outbound calls (subscribing users, applying tags, adding to sequences, looking up subscribers) works on Bubble's free tier. You only need a paid Bubble plan (Starter $32/mo+) if you want Backend Workflows — for example, to receive inbound webhooks from ConvertKit or to run scheduled subscriber sync jobs.

### Why are my subscribers appearing in ConvertKit but not in specific sequence reports?

In ConvertKit, subscribing to a form and subscribing to a sequence are separate API actions that produce separate attribution records. If you only call the sequence subscribe endpoint, subscribers appear in sequence analytics but not in form subscriber counts. If form attribution matters for your reporting, call both POST /forms/[form_id]/subscribe AND POST /sequences/[sequence_id]/subscribe in your Bubble Workflow.

---

Source: https://www.rapidevelopers.com/bubble-integrations/convertkit
© RapidDev — https://www.rapidevelopers.com/bubble-integrations/convertkit
