# IBM Watson

- Tool: Bubble
- Difficulty: Advanced
- Time required: 45–75 minutes
- Last updated: July 2026

## TL;DR

Connect Bubble to IBM Watson by first exchanging your IBM Cloud API key for a short-lived Bearer token via the IBM Cloud IAM endpoint, then using that token in the API Connector to call your Watson service. Each Watson service (NLU, Assistant, Discovery) has a unique instance URL — copy it from IBM Cloud credentials, not from documentation examples. Tokens expire after one hour; a Backend Workflow handles refresh automatically.

## IBM Watson's two-step auth and per-service URLs

IBM Watson authentication has two gotchas that trip up most Bubble developers. First, there is no single 'IBM Watson API URL' — each service instance has its own unique regional endpoint URL, and you must copy the exact URL from your IBM Cloud credentials screen. Documentation examples use placeholder URLs that will not work. Second, the IAM token grant type is urn:ibm:params:oauth:grant-type:apikey — a custom IBM extension to OAuth2 that Bubble's built-in OAuth2 authentication type cannot handle. You create a standard POST call in the API Connector with a form-encoded body to exchange your IBM Cloud API key for a Bearer token. This token is valid for approximately 3,600 seconds, after which it must be refreshed. A Bubble Backend Workflow handles this automatically, checking expiry and calling the token endpoint as needed before each Watson API call.

## Before you start

- An IBM Cloud account at cloud.ibm.com with at least one Watson service provisioned (e.g., Watson NLU, Watson Assistant, or Watson Discovery)
- An IBM Cloud API key generated from IAM → Manage → API Keys
- Your Watson service instance URL copied from IBM Cloud → Resource List → your service → Manage → Credentials
- Bubble app on Starter plan or above (Backend Workflows required for token refresh logic)
- Bubble's API Connector plugin installed (Plugins tab → Add plugins → search 'API Connector')

## Step-by-step guide

### 1. Get your IBM Cloud API key and Watson service instance URL

You need two pieces of information before touching Bubble: an IBM Cloud API key and the specific URL for your Watson service instance.

For the API key: log in to cloud.ibm.com, click your account name in the top right, go to Manage → Access (IAM) → API Keys → Create. Name it something like 'bubble-watson-key'. Copy the key immediately — IBM only shows it once. Store it somewhere safe (a password manager, not a text file).

For the Watson service URL: go to cloud.ibm.com → Resource List. Find your Watson service (e.g., 'Natural Language Understanding-my-instance'). Click it, then go to the Manage tab → Credentials. If no credentials exist, click 'New credential' to create one. Expand the credential to see the url field and apikey field. The URL looks like https://api.us-south.natural-language-understanding.watson.cloud.ibm.com/instances/abc12345-... — this is your instance-specific base URL and is the only correct URL for this service.

Critical: do not use URLs from Watson documentation examples — they're placeholders. The URL in your credentials is the one that works.

**Expected result:** You have your IBM Cloud API key and at least one Watson service instance URL copied and ready.

### 2. Create the IBM IAM token exchange call in the API Connector

In your Bubble editor, click Plugins tab → API Connector → Add another API. Name this group 'IBM IAM'. Leave Authentication as 'None or self-handled'.

Click 'Add a new call' and name it 'getIBMToken'. Set the method to POST and the URL to https://iam.cloud.ibm.com/identity/token.

Change the body type to 'x-www-form-urlencoded' (not JSON). Add the following body parameters:
- grant_type: urn:ibm:params:oauth:grant-type:apikey (this exact string — not client_credentials)
- apikey: your IBM Cloud API key (mark this field as Private)

Also add a shared header to this call: Accept: application/json.

Now click 'Initialize call'. Bubble will POST to IBM's IAM endpoint. If your API key is valid, you'll receive a response containing access_token, token_type: 'Bearer', expires_in: 3600, and scope. Bubble will parse these fields for use in workflows.

If initialization fails, the most common cause is using the wrong grant_type — confirm it is the full URN string urn:ibm:params:oauth:grant-type:apikey, not the short form apikey or client_credentials.

```
{
  "method": "POST",
  "url": "https://iam.cloud.ibm.com/identity/token",
  "headers": {
    "Accept": "application/json",
    "Content-Type": "application/x-www-form-urlencoded"
  },
  "body": {
    "grant_type": "urn:ibm:params:oauth:grant-type:apikey",
    "apikey": "<private: your_ibm_api_key>"
  }
}
```

**Expected result:** The initialize call returns a JSON response with access_token, expires_in: 3600, and token_type: Bearer. Bubble shows these fields as parseable response data.

### 3. Build a Backend Workflow to fetch and store the Bearer token

With the token exchange call working, you need a Backend Workflow that calls it and stores the resulting token for use in Watson API calls. Backend Workflows run on Bubble's servers and are required here — they're available on Bubble Starter plan and above.

Go to the Backend Workflows section of your Bubble editor (find it in the left sidebar or under Settings → API → 'This app exposes a Workflow API'). Create a new API workflow and name it 'refreshIBMToken'. Set it to run when triggered by a client-side workflow.

In the Backend Workflow, add these steps:
1. Call the 'IBM IAM - getIBMToken' API action
2. Add a 'Make changes to a Thing' step — targeting the current User (or an App-level Settings Thing if your app isn't user-based). Set the user's 'ibm_access_token' field (Text) to the API response's access_token value. Set the 'ibm_token_expiry' field (Date) to Current date/time + 3550 seconds (50 seconds buffer before the 3600-second actual expiry).

In your Data tab, make sure the User data type (or your Settings Thing) has these two fields: ibm_access_token (Text, Private) and ibm_token_expiry (Date).

Then, in your page's 'Page is loaded' workflow, add a conditional trigger: if Current User's ibm_token_expiry is empty OR Current User's ibm_token_expiry < Current date/time, schedule the 'refreshIBMToken' Backend Workflow. This ensures you always have a valid token before making Watson calls.

**Expected result:** The refreshIBMToken Backend Workflow runs successfully on page load, stores the access_token and expiry in the User record, and the token is available for Watson API calls.

### 4. Configure the Watson NLU API group and add the analyze call

Now set up the actual Watson service API group. Click API Connector → Add another API. Name it 'Watson NLU' (or 'Watson Assistant' depending on your service). Leave Authentication as 'None or self-handled'.

Under Shared headers, add an Authorization header. Set the value to Bearer (with a space), then add a parameter token of type 'Private'. The default value for this parameter will be dynamically set in workflows — don't hardcode it here. Also add Content-Type: application/json as a shared header.

Set the Base URL to your Watson NLU instance URL from Step 1, for example: https://api.us-south.natural-language-understanding.watson.cloud.ibm.com/instances/{your-instance-id}

Click 'Add a new call' and name it 'analyzeText'. Set method to POST and path to /v1/analyze. Add a default query parameter: version=2022-04-07 (the version date is REQUIRED — Watson NLU returns 400 without it).

In the body, add this JSON:
{
  "text": "<dynamic: input_text>",
  "features": {
    "sentiment": {},
    "entities": { "limit": 5 }
  }
}

For the initialize call, you need to provide a real text string and use a real Bearer token. Since the token lives in the database, temporarily set a real token as the default for the Private parameter, run the initialize call to let Bubble parse the response shape, then remove the hardcoded token (it will be injected dynamically in workflows). The response will contain sentiment.document.label and sentiment.document.score, plus an entities array.

```
{
  "method": "POST",
  "url": "https://api.us-south.natural-language-understanding.watson.cloud.ibm.com/instances/{instance_id}/v1/analyze?version=2022-04-07",
  "headers": {
    "Authorization": "Bearer <private: token>",
    "Content-Type": "application/json"
  },
  "body": {
    "text": "<dynamic: input_text>",
    "features": {
      "sentiment": {},
      "entities": { "limit": 5 }
    }
  }
}
```

**Expected result:** Watson NLU API group is configured. The initialize call succeeds and Bubble can parse sentiment label, sentiment score, and entities array from the response.

### 5. Wire the Watson call into a Bubble workflow with dynamic token injection

Now connect the Watson API call to a real user action. Design a Bubble page with a MultiLine Input element for text to analyze and a Button labeled 'Analyze'. Add a Text element to show sentiment result and a Repeating Group for entities.

Click the Analyze button → workflow editor. Add steps in this order:

Step 1: Add a conditional check — Only when Current User's ibm_token_expiry < Current date/time OR is empty. If true, schedule the 'refreshIBMToken' Backend Workflow and add a pause step of 2 seconds to allow it to complete before the next step.

Step 2: Add the Watson NLU - analyzeText API call. In the parameter fields: set input_text to the MultiLine Input's value. Set the token parameter to Current User's ibm_access_token. The token is passed here at runtime as the Private parameter value, keeping it out of the browser while still being injected into the Authorization header by Bubble's server.

Step 3: Add a 'Set state' action to store the sentiment result in a Custom State on the page. Set the 'sentiment' custom state to the API response's 'sentiment.document.label' path.

Step 4: Add a 'Display list' action to populate the Repeating Group with the API response's entities array.

In the Text element showing sentiment, set the content to the Custom State value. In the Repeating Group, bind each cell to the entity type and text fields from the response. RapidDev's engineers have built NLP dashboards exactly like this with Watson — if you need help mapping your specific Watson response structure, reach out at rapidevelopers.com/contact.

**Expected result:** Clicking Analyze sends the text to Watson NLU, the sentiment label appears in the Text element, and detected entities display in the Repeating Group.

### 6. Add privacy rules for Watson data stored in Bubble

If your Bubble app stores Watson analysis results — for example, saving sentiment scores back to a customer record or logging analyzed text for auditing — you must configure privacy rules to prevent unauthorized access.

Go to Data tab → Privacy in your Bubble editor. Select the data type where you store Watson results. Add a rule that restricts reads to: 'Current User is the thing's creator' or an appropriate role check. This is important if the analyzed text includes customer data, feedback, or any personally identifiable information.

Also consider what happens to the ibm_access_token stored in the User record. Add a privacy rule to the User data type that makes ibm_access_token readable only by 'Current User' — preventing one user from reading another user's token through the API.

For production, confirm that Bubble's Logs tab does not display the raw IBM Bearer token. Since you've marked the token parameter as Private in the API Connector, it should be redacted in logs — but verify this in the Logs tab after a test run.

Rotate your IBM Cloud API key periodically in IBM Cloud → IAM → API Keys → Revoke and recreate. Update the Private parameter in Bubble's API Connector immediately after rotation.

**Expected result:** Privacy rules are set, token data is protected, and you've confirmed that Bearer tokens do not appear in Bubble's Logs output.

## Best practices

- Always mark your IBM Cloud API key as Private in the API Connector — this keeps it on Bubble's servers and out of browser network requests.
- Store the IBM Bearer token in the User data type (or a single-record AppConfig Thing) with an expiry timestamp, and check expiry before every Watson API call.
- Add a 50-second buffer to your token expiry check (refresh at 3550 seconds instead of 3600) to avoid race conditions between expiry and an in-flight API call.
- Create a separate API Connector group for each Watson service — Watson NLU, Watson Assistant, and Watson Discovery have different base URLs and response schemas, and mixing them in one group creates confusion.
- Always include the version date query parameter in Watson calls (e.g., version=2022-04-07) — Watson returns 400 errors without it, regardless of the validity of your Bearer token.
- Set Bubble privacy rules on any data type storing Watson analysis outputs, especially if the analyzed content includes personally identifiable information or sensitive business data.
- Monitor your Watson service usage in IBM Cloud → Resource List → your service → Plan — Lite tier services have monthly usage caps, and exceeding them causes API calls to start returning quota-exceeded errors.
- When building Watson Assistant integrations, manage session IDs carefully — each conversation needs a session created first (POST /sessions), and the session_id must be stored in a Custom State or database field to persist across user messages.

## Use cases

### Customer feedback sentiment analysis dashboard

Marketing and support teams pipe customer reviews or support ticket text through Watson NLU's sentiment and entities features to surface trends — displayed in a Bubble dashboard with Repeating Groups filtered by sentiment score and entity type.

Prompt example:

```
Build a Bubble page where I can paste a block of customer review text and click Analyze. Call Watson NLU with sentiment and entities features, then display the overall sentiment label (Positive/Negative/Neutral) and a list of detected entities in a Repeating Group below.
```

### AI chatbot powered by Watson Assistant

Non-technical founders who have trained a Watson Assistant can embed it in their Bubble app as a conversational UI — using Watson's session API to maintain conversation context across multiple user messages within the same session.

Prompt example:

```
Create a Bubble chat interface that starts a Watson Assistant session when the page loads, stores the session_id in a Custom State, and sends each user message to Watson's message endpoint. Display the assistant's response text in a scrollable message list.
```

### Document intelligence for internal knowledge bases

Operations teams with Watson Discovery instances can wire Bubble forms to query their indexed document collections — letting non-technical staff search internal knowledge bases and display relevant passages without accessing the Watson dashboard directly.

Prompt example:

```
Add a search input on the Bubble page. On search button click, POST the query text to our Watson Discovery collection query endpoint and show the top 5 passage results with confidence scores in a Repeating Group.
```

## Troubleshooting

### IBM IAM token exchange returns 400 Bad Request

Cause: The grant_type value is incorrect. IBM requires the exact string urn:ibm:params:oauth:grant-type:apikey — any variation (like apikey, client_credentials, or urn:ibm:params:oauth:grant-type:api-key with a hyphen) will fail.

Solution: In the API Connector's getIBMToken call body, double-check the grant_type value is exactly urn:ibm:params:oauth:grant-type:apikey — no spaces, no variations. Also confirm the body type is set to x-www-form-urlencoded, not JSON. IBM's token endpoint does not accept JSON bodies for this exchange.

### Watson NLU returns 400 Bad Request when calling /v1/analyze

Cause: The version query parameter is missing or incorrectly formatted. Watson NLU requires a version date in YYYY-MM-DD format as a URL parameter on every call.

Solution: In the API Connector call configuration, add version as a default URL parameter with value 2022-04-07 (or the version date documented for your service tier). This parameter must be present on every Watson NLU call — add it as a shared parameter at the API group level so it's automatically included in all calls.

### Watson calls fail with 401 after working earlier in the session

Cause: The IBM IAM Bearer token has expired. Tokens are valid for approximately 3,600 seconds (one hour). If the token refresh workflow didn't run, stored tokens become invalid.

Solution: Check your page load workflow — confirm the token expiry check is running correctly. Open the User record in Bubble's Data tab and check the ibm_token_expiry value. If it's in the past, the refresh workflow isn't triggering. Make sure the Backend Workflow 'refreshIBMToken' is published and active, and that the page load condition correctly checks Current User's ibm_token_expiry < Current date/time.

### There was an issue setting up your call during initialization

Cause: The initialize call requires a real, valid request that returns a successful Watson response. If the instance URL is wrong, the Bearer token is invalid, or the request body doesn't match Watson's expected schema, initialization will fail and Bubble can't parse the response shape.

Solution: Temporarily set a real, freshly-exchanged IBM Bearer token as the default for the Private parameter. Use a simple test body with a short text string (e.g., 'Hello world') and the sentiment feature only. After a successful initialize call that shows Bubble the response shape, remove or clear the hardcoded token value — it will be injected dynamically from the User's ibm_access_token field in actual workflow runs.

### Backend Workflows section is not visible in the editor

Cause: Backend Workflows require a paid Bubble plan. They are not available on the Free plan.

Solution: Upgrade to Bubble Starter plan or above. Backend Workflows are needed for the IBM IAM token refresh logic. Without them, you cannot automate token renewal, which means tokens will expire after one hour and Watson calls will start returning 401 errors.

## Frequently asked questions

### Why can't I use Bubble's built-in OAuth2 authentication type for IBM Watson?

IBM Cloud IAM uses a non-standard OAuth2 grant type: urn:ibm:params:oauth:grant-type:apikey. Bubble's OAuth2 authentication type only supports standard grant types (authorization_code and client_credentials). Since IBM's grant type doesn't match either standard, you must create a manual POST call in the API Connector with an x-www-form-urlencoded body to exchange your API key for a Bearer token.

### Do I use the same API key for all Watson services, or does each service have its own?

IBM Cloud uses a single IAM API key that grants access to all services in your account. However, each Watson service instance has its own unique URL — Watson NLU has a different URL from Watson Assistant and Watson Discovery. You use one API key for the IAM token exchange, then use the resulting Bearer token with each service's individual instance URL.

### What's the difference between the IBM Cloud API key and the Watson service credentials I see in IBM Cloud?

Your IBM Cloud Resource List → Credentials screen shows both a url and an apikey for each Watson service. The apikey here is a service-specific IAM key — it works the same way as your general IBM Cloud IAM API key, just scoped to that service. You can use either key for the IAM token exchange at iam.cloud.ibm.com/identity/token. The url in credentials is the unique instance URL you use as your API Connector base URL.

### What is the version date parameter in Watson NLU calls and which value should I use?

The version date is a required query parameter that tells Watson NLU which API version to use for the response schema. It's in YYYY-MM-DD format (e.g., 2022-04-07) and doesn't change to today's date — it's a fixed value that identifies the API version you're targeting. Check IBM's Watson NLU documentation for the latest stable version date, or use 2022-04-07 which is a well-tested stable version.

### Do Backend Workflows require a paid Bubble plan?

Yes. Backend Workflows are available on Bubble Starter plan and above — not on the Free plan. They are required for the IBM token refresh logic. Without a Backend Workflow, you cannot automate token renewal, and after one hour IBM Watson calls will start failing with 401 errors as the stored token expires.

### How do I set up Watson Assistant in Bubble if it requires session management?

Watson Assistant's conversational API requires creating a session before sending messages. Add two API calls to your Watson Assistant API Connector group: 'createSession' (POST /v2/assistants/{assistant_id}/sessions) and 'sendMessage' (POST /v2/assistants/{assistant_id}/sessions/{session_id}/message). When the chat page loads, trigger createSession and store the returned session_id in a Custom State. Each user message sends to sendMessage with that session_id. Watson maintains conversation context server-side as long as the session is active.

---

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