# SurveyMonkey

- Tool: Bubble
- Difficulty: Intermediate
- Time required: 3–4 hours
- Last updated: July 2026

## TL;DR

Connect Bubble to SurveyMonkey using the API Connector plugin with a long-lived Private App Bearer token. Bubble proxies all calls server-side so the token stays hidden. The key challenge is that SurveyMonkey returns answer choices as numeric IDs — a second API call maps those IDs to readable labels before you can store clean data in Bubble. API access requires the Advantage plan ($99/mo+).

## Pull survey responses and map answer labels inside Bubble

SurveyMonkey's REST API v3 is a powerful tool for pulling survey definitions and response data into a Bubble app — but it has a non-obvious design that catches most builders by surprise. The /responses/bulk endpoint does not return answer text directly. Instead, it returns answer choice IDs (numeric values like '12345678'), and you must call /surveys/[id]/details separately to get the question and choice definitions, then cross-reference the two datasets to produce human-readable answers.

This means a complete Bubble integration requires at least two coordinated API calls per survey, and a Backend Workflow to merge and store the results. The payoff is significant: your team gets a live survey response dashboard inside Bubble, survey data feeding directly into CRM records, or automated follow-up workflows triggered by specific answer patterns — all without manual CSV exports from SurveyMonkey.

Before starting, confirm your SurveyMonkey plan. API access requires the Advantage plan at $99/month or higher. Basic and free accounts return 403 errors from the API with no data.

## Before you start

- A SurveyMonkey Advantage plan or higher ($99/mo) — Basic and free plans do not include API access
- A developer account at developer.surveymonkey.com to create your Private App and generate an access token
- At least one existing survey in SurveyMonkey with responses (needed for the initialize call to detect field types)
- A Bubble account with the API Connector plugin installed (free, by Bubble)
- For webhook-based real-time notifications: a paid Bubble plan (Starter $32/mo+) to use Backend Workflows

## Step-by-step guide

### 1. Generate a SurveyMonkey Private App access token

The cleanest authentication approach for a Bubble integration is a Private App token — a long-lived Bearer token that does not expire, eliminating the need to manage token refresh cycles. To create one, navigate to developer.surveymonkey.com and log in with your SurveyMonkey Advantage account. Click 'My Apps' in the navigation, then click 'Add App'. Give the app a name (e.g., 'Bubble Integration') and importantly select 'Private App' as the app type. Private Apps are designed for server-to-server integrations and generate tokens linked to the account that created them — they do not require a user-facing OAuth consent flow.

After creating the app, click 'Settings' on the app card. You will see an 'Access Token' field with a long alphanumeric string. Copy this token and store it securely. Important: Private App tokens are tied to the SurveyMonkey account that created the developer app. If that account is deactivated or loses its Advantage plan, the token stops working immediately. Create the developer app with a dedicated service account email if your organization has multiple users.

**Expected result:** You have a long-lived Private App access token copied from developer.surveymonkey.com. The token does not expire and does not require refresh logic.

### 2. Configure the API Connector for SurveyMonkey

In your Bubble app editor, go to the Plugins tab, click 'Add plugins', search for 'API Connector' (the free plugin by Bubble), and install it. After installation, click the API Connector in your plugins list to open its configuration. Click 'Add another API' and name this API 'SurveyMonkey'. Set the Base URL to: https://api.surveymonkey.com/v3

Click 'Add a shared header'. In the Key field, enter: Authorization. In the Value field, enter: Bearer followed by a space and your access token (example: Bearer sm-abc123xyz). Check the 'Private' checkbox next to this header. This is the security-critical step — it tells Bubble to store and send this header from its servers only, so the Bearer token never appears in browser network responses or client-side JavaScript. The rate limit on the Advantage plan is approximately 120 requests per minute — well above what typical Bubble use cases require, but keep it in mind if building high-frequency polling.

```
{
  "api_name": "SurveyMonkey",
  "base_url": "https://api.surveymonkey.com/v3",
  "shared_headers": [
    {
      "key": "Authorization",
      "value": "Bearer YOUR_ACCESS_TOKEN_HERE",
      "private": true
    }
  ]
}
```

**Expected result:** The API Connector lists 'SurveyMonkey' with a Private Authorization: Bearer header. No calls have been added yet.

### 3. Add API calls for surveys list, survey details, and bulk responses

You need three API calls for a complete survey response integration. Add each by clicking 'Add another call' under your SurveyMonkey API.

Call 1 — 'get_surveys': GET /surveys. Set 'Use as' to Data. This returns a paginated list of all your surveys with IDs, titles, and metadata. Initialize the call — it should return your existing surveys immediately.

Call 2 — 'get_survey_details': GET /surveys/[survey_id]/details. The [survey_id] should be added as a dynamic path parameter in Bubble by clicking 'Add parameter' and checking that it appears in the URL path. Use as Data. This returns the complete survey structure including all questions and their answer choice definitions (the key to mapping choice IDs back to labels).

Call 3 — 'get_bulk_responses': GET /surveys/[survey_id]/responses/bulk. Use as Data. This returns response records including the respondent's answers. Default page size is 50 responses, maximum is 100. The response includes a 'per_page', 'page', and 'total' for pagination.

Initialize each call against a real survey that has at least one response. For the survey_id parameter during initialization, use the actual numeric ID of a survey from your account (visible in the SurveyMonkey URL when viewing a survey).

```
Call 1: GET https://api.surveymonkey.com/v3/surveys
Headers: Authorization: Bearer <private>
Use as: Data
Detects: data (list), links (pagination)

Call 2: GET https://api.surveymonkey.com/v3/surveys/[survey_id]/details
Headers: Authorization: Bearer <private>
Path param: survey_id (non-private, dynamic)
Use as: Data
Detects: id, title, pages (list of page objects with questions and choices)

Call 3: GET https://api.surveymonkey.com/v3/surveys/[survey_id]/responses/bulk
Headers: Authorization: Bearer <private>
Path param: survey_id (non-private, dynamic)
Query params: per_page=100, page=1
Use as: Data
Detects: data (list of response objects), total, per_page, page
```

**Expected result:** Three API calls are initialized and showing green status in the API Connector. Field types are detected for all three calls.

### 4. Create Survey_Response and Survey_Question Data Types

Go to the Data tab in your Bubble editor. You will create two Data Types to store clean, human-readable survey data after processing the API responses.

Data Type 1: 'Survey_Response'
Create a new type named Survey_Response with these fields:
- survey_id: Text
- respondent_email: Text
- date_created: Date
- raw_response_id: Text (SurveyMonkey's response ID for deduplication)
- total_time: Number (seconds the respondent took)
- processed: yes/no (tracks whether choice IDs have been mapped)

Data Type 2: 'Survey_Answer'
Create a second type named Survey_Answer with:
- survey_response: Survey_Response (linked)
- question_text: Text
- answer_text: Text (the human-readable label)
- choice_id: Text (the raw numeric ID from the API, for reference)

Also go to Data tab → Privacy for both new Data Types and set rules to restrict access to appropriate user roles. Raw survey response data is sensitive — ensure 'Everyone else' cannot read or search these records. Enable access only for your admin user group or a specific role.

```
Data Type: Survey_Response
Fields:
  - survey_id: Text
  - respondent_email: Text
  - date_created: Date
  - raw_response_id: Text
  - total_time: Number
  - processed: yes/no (default: no)

Data Type: Survey_Answer
Fields:
  - survey_response: Survey_Response
  - question_text: Text
  - answer_text: Text
  - choice_id: Text

Privacy rules for both:
  Everyone else → Find this in searches: No
  Everyone else → Read: No
  Admin role → All permissions: Yes
```

**Expected result:** Two Data Types exist — Survey_Response and Survey_Answer — with appropriate privacy rules and all fields configured.

### 5. Build a Backend Workflow to fetch, map, and store response data

The core challenge in this integration is mapping SurveyMonkey's numeric choice IDs to human-readable answer text. This requires two API calls in sequence: first get the survey details (to build the choice ID → label map), then get the bulk responses (to process each answer). A Backend Workflow is the right place for this processing logic.

Go to the Backend Workflows section of your Bubble editor. Create a new API Workflow named 'Sync_Survey_Responses' with two input fields: survey_id (text).

Step 1: Call the 'get_survey_details' API Connector call with survey_id = Workflow's survey_id input. This returns the full question/choice map.

Step 2: Call 'get_bulk_responses' with the same survey_id. This returns response records with numeric choice IDs.

Step 3: For each response in the bulk results, check if a Survey_Response with that raw_response_id already exists. If not, create a new Survey_Response record with the respondent's email and date.

Step 4: For each answer in the response, look up the matching choice text from Step 1's survey details data, then create a Survey_Answer record linked to the Survey_Response with the human-readable label. This cross-referencing step is what makes the data usable.

Note: Recursive Backend Workflows for paginating through more than 100 responses are available on paid Bubble plans. If you have large surveys, plan for this from the start. RapidDev's team has implemented this exact pattern for Bubble SaaS apps — if you need help with recursive pagination or choice-ID mapping logic at scale, reach out at rapidevelopers.com/contact.

```
Backend Workflow: Sync_Survey_Responses
Input: survey_id (text)

Step 1: Call API → SurveyMonkey - get_survey_details
  Parameter: survey_id = Workflow input survey_id
  Result name: survey_details

Step 2: Call API → SurveyMonkey - get_bulk_responses
  Parameter: survey_id = Workflow input survey_id
  Result name: bulk_responses

Step 3 [Repeat for each item in bulk_responses's data]:
  Only when: Search for Survey_Response where raw_response_id = current item's id, count = 0
  Create new Survey_Response:
    survey_id: Workflow input survey_id
    respondent_email: current item's metadata's contact_email
    date_created: current item's date_created
    raw_response_id: current item's id
    processed: no

Step 4: For each answer in each response:
  Look up question_text from survey_details pages → questions where id = answer's question_id
  Look up answer_text from question's answers/choices where id = answer's choice_id
  Create Survey_Answer:
    survey_response: newly created Survey_Response
    question_text: looked up question text
    answer_text: looked up choice label
    choice_id: answer's choice_id
```

**Expected result:** The Sync_Survey_Responses Backend Workflow runs successfully, creating Survey_Response and Survey_Answer records with human-readable answer text rather than numeric choice IDs.

### 6. Register a SurveyMonkey webhook for real-time response notifications

Polling the SurveyMonkey API on a schedule works, but for real-time response processing you can register a Bubble Backend Workflow as a SurveyMonkey webhook. When a respondent submits a survey, SurveyMonkey sends a POST request to your Bubble endpoint — your Backend Workflow processes the notification and can immediately trigger a sync or create a record.

In Bubble's Backend Workflows section, create a new API Workflow named 'SurveyMonkey_Webhook'. Click 'Detect request data' to configure the input schema. Open a separate browser tab, go to developer.surveymonkey.com → your app → Webhooks, and add a new webhook. Set the Subscription URL to your Bubble Backend Workflow URL, which follows the pattern: https://your-app-name.bubbleapps.io/api/1.1/wf/surveymonkey_webhook

Set the event type to 'response_completed'. Save the webhook in SurveyMonkey. SurveyMonkey will send a test ping to your endpoint — click 'Detect request data' in Bubble during this ping to capture the payload structure. The payload includes the survey ID and response ID but not the full response data — your Backend Workflow should use this trigger to call Sync_Survey_Responses with the survey_id from the payload, fetching the new response via the API.

Important: Backend Workflows and the Workflow API endpoint (api/1.1/wf/) require a paid Bubble plan. The free Bubble tier does not expose this endpoint. If you try to register the URL on the free tier, SurveyMonkey's webhook test ping will fail with no route found.

```
SurveyMonkey Webhook payload (response_completed event):
{
  "name": "response_completed",
  "filter_type": "survey",
  "filter_id": "123456789",
  "event_id": "abc-def-ghi",
  "event_type": "response_completed",
  "object_type": "response",
  "object_id": "987654321",
  "resources": {
    "collector_id": "111222333",
    "survey_id": "123456789",
    "user_id": "444555666",
    "response_id": "987654321"
  },
  "href": "https://api.surveymonkey.com/v3/surveys/123456789/responses/987654321"
}

Bubble Backend Workflow URL pattern:
https://your-app-name.bubbleapps.io/api/1.1/wf/surveymonkey_webhook
```

**Expected result:** SurveyMonkey shows the webhook as active with a green status. New survey completions trigger the Bubble Backend Workflow within seconds and create Survey_Response and Survey_Answer records automatically.

## Best practices

- Use a Private App token rather than attempting an OAuth redirect flow — Private App tokens are long-lived, non-expiring, and perfectly suited for server-side integrations like Bubble's API Connector. Always mark the Authorization header Private.
- Always call /surveys/[id]/details before processing /responses/bulk — the details endpoint contains the choice definition map required to translate numeric choice IDs into human-readable answer text.
- Implement deduplication using the SurveyMonkey response ID (raw_response_id) as a unique key in your Survey_Response Data Type. Check for existing records before creating new ones to prevent duplicates on repeat syncs.
- Set strict privacy rules on Survey_Response and Survey_Answer Data Types immediately. Survey response data is sensitive — ensure 'Everyone else' cannot read or search these records in Bubble's Data tab → Privacy section.
- Handle pagination for large surveys: the /responses/bulk endpoint returns 50 responses by default, max 100. Use the 'total' and 'page' fields in the response to calculate if additional pages exist, and implement recursive Backend Workflows for surveys with more than 100 responses.
- Create the developer app under a dedicated service account email rather than a personal account. If the account that owns the Private App is deactivated, the token stops working immediately with no warning.
- Be mindful of WU (Workload Units) costs in Bubble for the Backend Workflow that processes responses. Each step in the workflow consumes WU. Batch processing at off-peak hours and caching results in Data Types reduces both WU cost and SurveyMonkey API request count.
- Test your webhook integration with SurveyMonkey's developer portal webhook testing tool before going live. Send test pings to confirm your Bubble Backend Workflow URL is reachable and responding correctly.

## Use cases

### Customer feedback dashboard with human-readable answers

Pull NPS survey responses into a Bubble admin panel that displays each response with readable answer text rather than cryptic choice IDs. Use a Backend Workflow to fetch responses, map choice IDs to labels using the survey details endpoint, and store clean data in a Survey_Response Data Type for your team to filter, sort, and act on.

Prompt example:

```
Build a Bubble admin dashboard that fetches the latest 50 responses from a specific SurveyMonkey NPS survey, maps answer choice IDs to labels, stores them in a Survey_Response Data Type, and displays them in a sortable Repeating Group with NPS score and comment fields.
```

### Automated CRM update on survey completion

When a customer completes a satisfaction survey, automatically update their record in Bubble's database with their NPS score or satisfaction rating. Combine the SurveyMonkey API pull with a Backend Workflow that looks up the Bubble User by email from the survey response and updates their profile — no manual data entry required.

Prompt example:

```
Build a Bubble Backend Workflow triggered by a SurveyMonkey response webhook that reads the new response, looks up the respondent's email in Bubble's User Data Type, and updates their nps_score and last_survey_date fields.
```

### Event registration form with follow-up survey management

For event apps built in Bubble, pull event feedback survey results directly into the event record after the event date. Display aggregate results (average ratings by question) in the event admin view alongside registration counts and attendance data — all without leaving Bubble.

Prompt example:

```
When an event's date passes in my Bubble app, trigger a Backend Workflow that fetches all responses from the linked SurveyMonkey survey, calculates average ratings per question, and stores results in the Event's analytics field.
```

## Troubleshooting

### API calls return 403 Access Denied even with a valid-looking token

Cause: SurveyMonkey API access requires the Advantage plan ($99/mo+). Basic and free accounts return 403 with no helpful message. This is the most common cause of connection failures for this integration.

Solution: Log in to surveymonkey.com and check your plan under Account Settings → Billing. If you are on a Basic or free plan, you need to upgrade to Advantage before any API calls will work. After upgrading, regenerate your Private App token in developer.surveymonkey.com — existing tokens on downgraded accounts may not activate immediately on upgrade.

### Initialize call fails with 'There was an issue setting up your call' for survey details or bulk responses

Cause: The initialize call requires a real survey ID and for bulk responses, at least one completed response. If you used a placeholder survey ID or a survey with zero responses, Bubble cannot detect the response shape.

Solution: Find a survey ID from your SurveyMonkey account that has at least one completed response. The survey ID is visible in the URL when you open the survey in SurveyMonkey (e.g., surveymonkey.com/summary/123456789 — the number is the ID). Use this real ID as the initialization value for both the get_survey_details and get_bulk_responses calls.

### Answer data in Bubble shows numeric IDs instead of readable text (e.g., '12345678' instead of 'Very Satisfied')

Cause: The /responses/bulk endpoint returns answer choice IDs, not choice text. The mapping step (calling /surveys/[id]/details and cross-referencing choice IDs) was not implemented in the Backend Workflow.

Solution: In your Sync_Survey_Responses Backend Workflow, add the get_survey_details call as the first step. From the details response, navigate to pages → questions → answers to build the choice ID to label map. When creating Survey_Answer records, look up the answer_text by matching the choice_id from the response against the choices in the survey details response. If Bubble's auto-detected fields for the nested structure are incorrect, check the field names in the Logs tab → API calls section to see the actual response structure.

### The SurveyMonkey webhook test ping fails and shows no route found

Cause: Backend Workflow endpoints (the api/1.1/wf/ URL) require a paid Bubble plan. The free Bubble tier does not expose this endpoint, so SurveyMonkey's ping returns a 404.

Solution: Upgrade to a paid Bubble plan (Starter $32/mo+) to enable Backend Workflows and the Workflow API. Once upgraded, go to Settings → API in your Bubble editor and enable 'This app exposes a Workflow API'. Re-run the SurveyMonkey webhook test ping after enabling this setting.

### Duplicate Survey_Response records are created when the sync workflow runs multiple times

Cause: The workflow is not checking whether a Survey_Response with the same raw_response_id already exists before creating a new record.

Solution: Add an 'Only when' condition on the Create Survey_Response step: 'Search for Survey_Response items where raw_response_id = current response's id, count is 0'. This ensures a new record is created only when no existing record has that response ID. Consider also adding a unique constraint note in Bubble documentation since Bubble does not natively enforce unique field values.

## Frequently asked questions

### Can I use SurveyMonkey's API on the free or Basic plan?

No. SurveyMonkey's API requires the Advantage plan ($99/month) or higher. Free and Basic accounts do not have API access, and calls from those accounts return a 403 Access Denied error. You need to upgrade before any Bubble integration work will succeed.

### Do I need to implement OAuth to use SurveyMonkey with Bubble?

No. The recommended approach is a Private App token, which is a long-lived Bearer token generated in the SurveyMonkey developer portal. It does not expire and does not require an OAuth redirect flow — which Bubble cannot natively execute inside a workflow. Create a Private App at developer.surveymonkey.com, copy the Access Token, and place it in a Private Authorization header in the API Connector.

### Why does my survey response data show numbers instead of answer text?

SurveyMonkey's /responses/bulk endpoint returns answer choice IDs (numeric values) rather than the actual text of each answer option. To get readable labels, you must call /surveys/[id]/details to retrieve the full question and choice definitions, then cross-reference the choice IDs in each response against that map. This two-step process is required for any integration that needs to display or store human-readable answers.

### Do I need a paid Bubble plan to use this integration?

For outbound API calls (pulling survey lists, question definitions, and responses), the free Bubble tier is sufficient. You only need a paid Bubble plan (Starter $32/mo+) if you want to use Backend Workflows — which are required for inbound SurveyMonkey webhooks (real-time response notifications) and for complex processing workflows that run server-side.

### How do I handle more than 100 survey responses in Bubble?

The SurveyMonkey /responses/bulk endpoint returns a maximum of 100 responses per page. The response includes 'total', 'per_page', and 'page' fields. To retrieve all responses, calculate the number of pages (total / per_page, rounded up), then use recursive Backend Workflows in Bubble that call the endpoint incrementing the page parameter until all responses are fetched. Recursive Backend Workflows require a paid Bubble plan.

### What happens if the SurveyMonkey account that owns the developer app is closed?

The Private App token stops working immediately when the account is closed or loses its Advantage plan. This is a significant operational risk. To mitigate it, create the developer app under a dedicated service account email (like api-service@yourcompany.com) rather than a personal employee email. Also document the token location so it can be regenerated quickly if the account situation changes.

---

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