Doodle's REST API v2 is restricted to enterprise partners — independent developers and small businesses cannot obtain API credentials. This tutorial covers two practical alternatives: (1) embedding a Doodle poll inside a Bubble HTML element via iframe, and (2) building a fully functional group scheduling poll natively in Bubble using two Data Types and standard workflows. The custom Bubble poll is the recommended production path for most use cases.
| Fact | Value |
|---|---|
| Tool | Doodle |
| Category | Productivity |
| Method | Bubble API Connector |
| Difficulty | Beginner |
| Time required | 1–3 hours (widget embed: 30 min; custom Bubble poll: 2–3 hours) |
| Last updated | July 2026 |
The Honest Guide: Doodle API Is Partner-Gated — Here Are the Two Real Options
Doodle is one of the most-searched scheduling integrations — and one of the most common dead ends for Bubble developers. The Doodle REST API v2 at developer.doodle.com uses OAuth 2.0, but API access is restricted to enterprise partners. If you fill out the API access request form, you will receive a response asking about your enterprise partnership status. Independent app developers, startups, and small businesses building on Bubble cannot obtain credentials through the standard registration flow. This is not a documentation gap — it is Doodle's confirmed API distribution policy as of 2026.
Knowing this upfront saves hours of debugging a dead-end OAuth flow. There are two real paths forward depending on your use case:
**Path 1: Doodle iframe embed** — If you want Doodle's specific scheduling UI and brand inside your Bubble app (and you already have a Doodle poll URL), you can embed it in a Bubble HTML element. This takes about 30 minutes. The limitation: the poll lives in Doodle's system, participants vote in Doodle's interface, and Bubble has no access to the vote data. You cannot query results, trigger workflows on new votes, or store participant answers in Bubble's database.
**Path 2: Custom Bubble scheduling poll** — Build a fully functional group availability poll directly in Bubble using two Data Types (SchedulingPoll and SchedulingVote) and standard Bubble workflows. This is the production-ready path for most use cases: all data is in your Bubble database, you can query it, trigger emails on new votes, calculate winning slots automatically, and customize the UI completely. It takes 2–3 hours to build from scratch.
If your actual need is one-on-one meeting scheduling (not group polls), Calendly is the better choice: it has a fully public REST API with OAuth 2.0 Bearer tokens, self-service credential creation at developer.calendly.com, and direct calendar integration. That is a genuinely buildable API integration for Bubble.
This tutorial walks through both the embed path and the full custom poll build, so you can choose the right approach for your situation.
Integration method
Doodle's REST API v2 is partner-gated (not available to independent developers). The practical paths are an iframe widget embed via Bubble's HTML element, or a custom scheduling poll built natively with Bubble's database.
Prerequisites
- A Bubble account (Free plan is sufficient for both the embed path and the custom poll build)
- For the embed path: an existing Doodle poll URL (create one free at doodle.com)
- For the custom poll path: no external accounts needed — everything is built in Bubble's native database
- Optional for email notifications: a SendGrid or Mailgun API key configured in Bubble's API Connector
Step-by-step guide
Understand the Limitation — and Choose Your Path
Before attempting any API Connector setup for Doodle, confirm that your use case does not require Doodle's API. Visit https://developer.doodle.com in your browser. If you attempt to register as a developer, you will encounter an enterprise partner requirement — standard developer accounts are not provisioned. This is the current state of Doodle's API access policy as of 2026. As a result, there is no standard Bubble API Connector setup for Doodle that will work for independent developers. Do not spend time trying to build an OAuth flow — the credential acquisition step is blocked before you can write a single line of configuration. Instead, decide which path fits your use case: **Choose the iframe embed if:** - You already have or will create Doodle polls manually in Doodle's interface - You just want Doodle's UI to appear inside your Bubble app - You do not need vote data in Bubble's database - You are prototyping or building an MVP and speed matters **Choose the custom Bubble poll if:** - You want all scheduling data in Bubble's database - You need to trigger workflows on new votes (send emails, update records) - You want to customize the scheduling UI with your own branding - You need to query or report on poll results from Bubble - You are building a production app used by real clients or team members **Choose Calendly if:** - Your primary need is one-on-one meeting booking (not group polls) - You want real calendar integration (Google Calendar, Outlook) - You want a fully functional REST API integration in Bubble The rest of this tutorial covers both the embed path (Steps 2–3) and the custom Bubble poll path (Steps 4–6).
Pro tip: If you specifically need Doodle's group poll feature inside a Bubble enterprise app and your organization qualifies as an enterprise Doodle customer, contact Doodle's enterprise sales team at doodle.com/enterprise to inquire about API partner access. This is the only viable path to using Doodle's REST API.
Expected result: You have decided which path to follow based on your use case requirements. If you need the embed path, you have a Doodle poll URL ready. If you need the custom poll path, you are ready to create Data Types in Bubble.
[Embed Path] Add a Doodle Poll via HTML Element in Bubble
If you have chosen the embed path, this step creates the Doodle poll view inside your Bubble page using Bubble's HTML element. First, create your Doodle poll in Doodle's own interface at doodle.com. Log in, click 'Create a Doodle', set up your time options, and publish the poll. Copy the poll participation URL — it looks like https://doodle.com/meeting/participate/id/{pollId} or a similar format depending on Doodle's current URL structure. In your Bubble editor, open the page where you want the poll to appear. Click the '+' button (Add elements) → HTML element. Draw the HTML element on the page at the desired size — Doodle's scheduling interface needs enough height to display time options comfortably (at least 500px tall is recommended). Click on the HTML element to open its properties and paste the following iframe code into the content field: ```html <iframe src="https://doodle.com/meeting/participate/id/{YOUR_POLL_ID}" width="100%" height="100%" frameborder="0" style="border: none; min-height: 480px;"> </iframe> ``` Replace {YOUR_POLL_ID} with the actual poll ID from your Doodle poll URL. Adjust the height value to fit your page layout. Limitations to communicate to users: the poll is rendered in an iframe served from Doodle's servers. Participants interact with Doodle's interface — Bubble does not receive any data about who voted or which options they selected. Doodle's branding appears inside your page. If Doodle changes its URL structure or embed policy, the iframe will break and you will need to update the embed code. There is no way to trigger a Bubble workflow when a participant submits their vote through this embed. For a branded, controlled scheduling experience where you capture vote data — proceed to Steps 4–6 for the custom Bubble poll.
1<iframe 2 src="https://doodle.com/meeting/participate/id/{YOUR_POLL_ID}" 3 width="100%" 4 height="560px" 5 frameborder="0" 6 style="border: none; border-radius: 4px;">7</iframe>Pro tip: Doodle's embed may not display correctly inside very narrow containers. Set the HTML element's minimum width to 320px and test on mobile viewports — Doodle's responsive layout requires enough horizontal space for the time-slot columns to render properly.
Expected result: A Doodle poll appears inside your Bubble page in the HTML element area. Participants can interact with the scheduling interface without leaving the Bubble app. The poll link matches your Doodle poll's actual ID.
[Embed Path] Handle Doodle's Existing Poll Results Display
If you have chosen the embed path and want to show poll results (not just the voting view), Doodle provides a results URL for completed polls. The results view is accessible at a different URL format that shows the aggregated availability. In Doodle's interface, after participants have voted, navigate to the poll results page — Doodle shows a summary of which time slots have the most availability. The results page URL typically has a different format from the voting URL. In Bubble, add a second HTML element (or a toggle-able Group containing an HTML element) with the Doodle results URL embedded as an iframe. Add a Button labeled 'View Results' that toggles the visibility of the results Group versus the voting Group. For a tabbed interface: create two Groups — 'Voting View' and 'Results View' — each containing an HTML element with the respective Doodle iframe. Add a workflow triggered by a 'Show Results' button that hides the Voting View Group and shows the Results View Group. Important reminder: this entire embed approach means all scheduling logic lives in Doodle's system. Bubble's database has no record of poll participants, votes, or results. If you ever need to programmatically access this data (to send automated follow-up emails, integrate with a calendar, or archive results), you cannot do so through the embed — you would need the custom poll approach from Steps 4–6 instead. For the custom Bubble poll path, skip this step and continue to Step 4.
1<!-- Voting view iframe -->2<iframe 3 src="https://doodle.com/meeting/participate/id/{POLL_ID}" 4 width="100%" height="560px" frameborder="0">5</iframe>67<!-- Results view iframe (different URL format) -->8<iframe 9 src="https://doodle.com/meeting/organize/id/{POLL_ID}" 10 width="100%" height="560px" frameborder="0">11</iframe>Pro tip: If Doodle's iframe shows a blank white area or a 'Refused to connect' error, Doodle may have updated its iframe embed policy or URL format. Check doodle.com for current embed documentation or use the direct Doodle link instead of an iframe.
Expected result: Your Bubble page has a tabbed interface — a 'Vote' tab showing the Doodle voting iframe and a 'Results' tab showing the Doodle results iframe. Both load correctly and display the real poll data from Doodle.
[Custom Poll Path] Create Data Types for Scheduling Poll and Votes
The custom Bubble poll gives you full control: all data lives in your Bubble database, you can query it in workflows, and you can build any UI you want. Start by creating the two core Data Types. Go to the Data tab in the Bubble editor. Click 'Add a type'. **Data Type 1: SchedulingPoll** Fields to add: - title (text) — the poll's name or meeting title - organizer_email (text) — who created the poll (for notification purposes) - time_slots (list of text) — the proposed time options (e.g., ['Mon Jan 12 10am', 'Mon Jan 12 2pm', 'Tue Jan 13 11am']). Using a list of text allows flexible slot descriptions. - expiry_date (date) — when voting closes - unique_id (text) — a randomly generated ID for the shareable link (use Bubble's 'Generate random string' or a UUID to populate this on creation) - is_closed (yes/no) — whether the organizer has closed voting **Data Type 2: SchedulingVote** Fields to add: - poll (SchedulingPoll) — which poll this vote belongs to - participant_name (text) — voter's name - participant_email (text) — voter's email (used for duplicate prevention) - selected_slots (list of text) — which time slots the participant marked as available - created_date (date) — timestamp of the vote **Privacy rules:** Go to Data tab → Privacy for each type. For SchedulingPoll: add a rule — 'Everyone can see this field' for title, time_slots, expiry_date, unique_id, and is_closed. Restrict organizer_email to 'logged in users only' or hide it entirely from the voting UI. For SchedulingVote: allow anyone to create a new vote (for anonymous voting); restrict search/list to 'logged in users only' (organizers only see all votes — participants do not see each other's responses). Add a constraint: 'Only when the voter's email field doesn't equal an existing vote's email for the same poll' — this is enforced in the workflow, not the privacy rule.
Pro tip: Using a 'list of text' for time_slots is simpler than creating a separate TimeSlot Data Type for most scheduling polls. If you need to track rich metadata per slot (e.g., timezone, duration, location), create a dedicated TimeSlot Data Type instead and link it to SchedulingPoll.
Expected result: Two Data Types appear in Bubble's Data tab: SchedulingPoll with title, organizer_email, time_slots, expiry_date, unique_id, and is_closed fields; and SchedulingVote with poll, participant_name, participant_email, selected_slots, and created_date fields. Privacy rules are configured to allow anonymous voting while restricting vote-list access to organizers.
[Custom Poll Path] Build Poll Creation and Voting Pages
With the Data Types in place, build two pages: a Poll Creation page for organizers and a Voting page for participants. **Poll Creation Page (page name: create-poll)** Add the following elements: - An Input element for Poll Title (connected to a Custom State: poll_title) - An Input element for Organizer Email - A Date Picker for Expiry Date - A Repeating Group or a dynamic text input section for time slots — simplest approach: add 5 Input elements (Slot 1 through Slot 5) and let the organizer fill in as many as they want. Or use a Repeating Group with a Custom State list that starts with 3 slots and an 'Add another slot' button - A Button labeled 'Create Poll' Poll creation workflow (triggered by the 'Create Poll' button): 1. Action: Create a new SchedulingPoll → set title = Poll Title input's value, organizer_email = Organizer Email input's value, expiry_date = Date Picker's value, time_slots = list of all non-empty slot inputs, unique_id = generate a random string (use Bubble's 'Random string' feature or a workflow expression that combines timestamp + random characters), is_closed = 'no' 2. Action: Navigate to the Voting page (see below) with the new poll's unique_id as a URL parameter 3. Optional: Copy-to-clipboard workflow that generates the shareable voting link: https://yourapp.bubbleapps.io/vote?poll_id={unique_id} **Voting Page (page name: vote)** This page receives the poll's unique_id as a URL parameter (page parameter: poll_id). Use 'Get data from page URL' to fetch the matching SchedulingPoll where unique_id = URL parameter poll_id. Add these elements: - A Text element showing the poll title (from the found SchedulingPoll) - A Repeating Group displaying the SchedulingPoll's time_slots list. Each cell shows the slot text and a Checkbox element. - Input fields for participant_name and participant_email - A Button labeled 'Submit My Availability' Voting workflow (triggered by 'Submit My Availability'): 1. Condition check: search for SchedulingVotes where poll = current SchedulingPoll AND participant_email = the Email input's value. If this count > 0, show an alert: 'You have already submitted your availability for this poll.' Stop the workflow. 2. Condition check: if the SchedulingPoll's is_closed = yes or expiry_date < Current date/time, show an alert: 'This poll is closed.' Stop the workflow. 3. Action: Create a new SchedulingVote → set poll = found SchedulingPoll, participant_name = Name input, participant_email = Email input, selected_slots = list of all Checkbox cells where the checkbox is checked (collect the time_slot text from each checked cell), created_date = Current date/time 4. Action: Show a confirmation message: 'Thank you! Your availability has been recorded.' RapidDev's team has built custom scheduling tools in Bubble for service businesses and team coordination apps — if you need to extend this poll with calendar sync or automated email reminders, get a free scoping call at rapidevelopers.com/contact.
Pro tip: For the Checkboxes in the Voting Repeating Group, use a Custom State (type: list of text) on the page named 'selected_slots'. When a checkbox is checked, add the current cell's slot text to the list; when unchecked, remove it. Use this Custom State as the selected_slots value when creating the SchedulingVote record.
Expected result: The create-poll page allows an organizer to create a poll with time slots and receive a shareable link. The vote page displays the poll's time options as checkboxes, collects the participant's name and email, prevents duplicate votes from the same email, and creates a SchedulingVote record on submission.
[Custom Poll Path] Build the Results Page with Slot Rankings
The Results page shows the organizer (and optionally participants) which time slot has the most availability. Create a new page named 'poll-results' that accepts the poll's unique_id as a URL parameter. Fetch the SchedulingPoll: use 'Get data from page URL' → search SchedulingPoll where unique_id = URL parameter poll_id. Display vote summary: add a Repeating Group with the SchedulingPoll's time_slots list as data source. In each cell: - Show the slot text (current cell's text value from the time_slots list) - Show the vote count for this slot: 'Do a search for SchedulingVotes where poll = current SchedulingPoll AND selected_slots contains current cell's text' → count - Show a visual indicator — a progress bar Group whose width is proportional to (this slot's vote count / total participant count × 100%) Sort the Repeating Group by vote count descending to show the most popular slot first. Since Repeating Groups sorted by a calculated value (not a stored field) can be tricky in Bubble, consider storing the vote counts in a custom state or using a 'Sorted by' custom expression. Total participant count: display 'Do a search for SchedulingVotes where poll = current SchedulingPoll' → count. Winning slot announcement: add a Text element visible only when vote data is loaded: 'Best availability: [slot with highest vote count]'. Use a conditional to show this only when at least one vote exists. Close poll button: add a Button labeled 'Close Voting' visible only to the organizer (add a condition: current page's URL parameter 'organizer' = a value set when creating the poll, or use Bubble's User auth if organizers log in). The workflow: make changes to SchedulingPoll → set is_closed = yes. Privacy consideration: the Results page should be accessible to anyone with the poll link if you want participants to see the aggregate results. If results should be organizer-only, add a URL parameter check or require login. For anonymous public polls, make the Results page publicly accessible but ensure individual votes (SchedulingVote records) are not directly queryable from the public-facing UI — only the aggregate counts.
Pro tip: To display a progress bar proportional to votes, add a Group element inside the Repeating Group cell and set its width using a conditional: when 'Search for SchedulingVotes (filtered) count / total votes count' × bar container width. This creates a simple visual comparison without any external charting library.
Expected result: The poll-results page shows all time slots ranked by vote count, with a visual progress bar for each slot showing relative popularity. The total participant count displays correctly. The 'Close Voting' button marks the poll as closed. The winning slot (most votes) is highlighted at the top of the list.
Common use cases
Embed an Existing Doodle Poll in a Bubble Portal
If you already use Doodle for team scheduling and just want the poll to appear inside a Bubble member portal or dashboard without leaving the app, embedding the Doodle iframe is the fastest path. Participants interact with Doodle's native UI inside your Bubble page. No data flows into Bubble's database.
How do I embed a Doodle poll inside a Bubble page so participants can vote without leaving my Bubble app? I have the Doodle poll URL already.
Copy this prompt to try it in Bubble
Custom Group Availability Poll Built in Bubble
Build a full group scheduling poll natively in Bubble: organizers create polls with time slot options, share a link with participants, collect anonymous or authenticated votes, and view ranked results showing which slot has the most availability. All data stays in Bubble's database for querying, reporting, and workflow triggers.
I want to build a group availability poll in Bubble where an organizer sets time options, participants vote on their available slots, and the system shows which time slot works best for everyone. How do I structure the data and workflows?
Copy this prompt to try it in Bubble
Meeting Coordination Widget for a Client Portal
Add a scheduling module to a Bubble client portal where clients can indicate their availability for an upcoming meeting across several proposed time slots. Combine with a SendGrid email workflow that notifies the organizer when all expected participants have voted, and displays the winning slot automatically.
Build a Bubble scheduling widget where an admin proposes 5 meeting time slots, invites 3 clients via email link, and automatically shows the best slot once all clients have voted. Include a SendGrid notification to the admin when voting is complete.
Copy this prompt to try it in Bubble
Troubleshooting
Attempted to register for Doodle API access at developer.doodle.com and received an enterprise partner inquiry instead of credentials
Cause: Doodle's REST API v2 is restricted to enterprise partners. Independent developers and small businesses cannot obtain OAuth credentials through the self-service registration form. This is Doodle's confirmed distribution policy as of 2026, not a temporary outage or documentation error.
Solution: Follow either the iframe embed path (Steps 2–3) or the custom Bubble poll path (Steps 4–6) described in this tutorial. If your organization qualifies as an enterprise Doodle customer, contact Doodle's enterprise sales team at doodle.com/enterprise to inquire about API partner access. For most Bubble developers, the custom Bubble poll is the correct solution.
The Doodle iframe embed shows a blank area or 'Refused to connect' error in the Bubble HTML element
Cause: Doodle may have updated its Content Security Policy or iframe embedding policy to block embedding in third-party domains. This can happen without notice and affects all iframe-based Doodle embeds.
Solution: Check doodle.com's current embed documentation. If Doodle no longer supports iframe embedding, switch to a direct link approach: instead of embedding the poll, add a Button in Bubble that opens the Doodle poll URL in a new browser tab (use Bubble's 'Open an external website' action). Alternatively, switch to the custom Bubble poll path (Steps 4–6) to eliminate the dependency on Doodle's embed availability.
Duplicate votes are being created — the same email address appears multiple times in SchedulingVote records
Cause: The duplicate-vote check at the start of the voting workflow is not running correctly. This can happen if the condition is checking the wrong field, if the email input is empty when the check runs, or if the workflow steps are in the wrong order.
Solution: In the voting workflow, ensure the duplicate-check condition is the FIRST step before the 'Create SchedulingVote' action. The condition should be: 'Only when Search for SchedulingVotes where poll = [current poll] AND participant_email = [email input value]:count is 0'. If the count is greater than 0, show an error message and stop the workflow using an 'Only when' condition or a 'Terminate this workflow' step. Also add an 'Only when' condition on the 'Create SchedulingVote' action itself as a safety net.
The vote count on the Results page shows 0 for all slots even though SchedulingVote records exist
Cause: The search filter on the Results page Repeating Group is not correctly matching the slot text. The 'selected_slots contains [current cell text]' condition is case-sensitive and requires an exact match — any formatting difference between how the slot was stored in SchedulingPoll's time_slots list and how it appears in SchedulingVote's selected_slots list will cause a count of 0.
Solution: Verify that the slot text stored in SchedulingVote's selected_slots list exactly matches the text in SchedulingPoll's time_slots list. Open the Bubble Data editor (Data tab → App data) and compare the raw values. If there are whitespace differences or character encoding issues, standardize the slot text by trimming whitespace in the creation workflow before storing.
The voting page shows 'No poll found' even though the poll was just created and the link was shared
Cause: The voting page's URL parameter lookup is not matching the SchedulingPoll's unique_id field. This can happen if the shareable link was constructed with a different parameter name than what the voting page expects, or if the unique_id was not saved correctly during poll creation.
Solution: Open the Bubble Data editor → SchedulingPoll and check that the most recently created poll has a non-empty unique_id field. Confirm the shareable link format matches the URL parameter name in the voting page's 'Get data from page URL' configuration. If the unique_id is empty, the poll creation workflow's 'generate random string' step did not run — check the workflow action order and verify the unique_id field is being set before the navigation action.
Best practices
- Lead with honesty about Doodle's API restriction — any Bubble app that attempts to build an API Connector integration with Doodle using self-service credentials will fail at the credential-acquisition step. Choosing the correct alternative path (embed vs custom poll) upfront saves hours of dead-end debugging.
- For the custom Bubble poll, always implement duplicate-vote prevention as a workflow condition before the 'Create SchedulingVote' action — not as a privacy rule alone. Privacy rules control data visibility, not the creation of duplicate records. A workflow condition is the correct enforcement layer.
- Add expiry date enforcement on the voting page: check that SchedulingPoll's expiry_date > Current date/time and is_closed = no before allowing a vote submission. Without this check, votes can be submitted after the organizer has closed the poll.
- Use a randomly generated unique_id (not the Bubble record's internal _id) for the shareable poll link. This gives you control over the URL format, makes links shorter and more user-friendly, and prevents exposing internal database IDs in URLs.
- Set privacy rules on SchedulingVote to prevent participants from seeing each other's availability responses. The Results page should show aggregate vote counts per slot (how many people are available) without revealing which specific participants selected each slot, unless your use case explicitly requires participant-level transparency.
- If you need email notifications when votes are submitted (e.g., notify the organizer when all expected participants have voted), use SendGrid or Mailgun via Bubble's API Connector rather than Backend Workflows if possible — the notification logic can run as a client-side workflow action after the vote is created. Backend Workflows (paid plan) are only required if you need server-side email delivery or scheduled follow-up reminders.
- Consider Calendly as the correct choice for one-on-one meeting scheduling with real calendar integration. Doodle's model (group polls, manual voting, no calendar sync) and Calendly's model (availability-based booking, calendar integration, automated confirmation) solve fundamentally different problems — choose the tool that matches your actual scheduling pattern.
Alternatives
Calendly has a fully public REST API with OAuth 2.0 Bearer tokens — self-service developer app creation at developer.calendly.com, no enterprise partnership required. It focuses on one-on-one and group event booking based on real calendar availability (Google Calendar, Outlook integration), automated confirmation emails, and webhook notifications for new bookings. If your use case is meeting scheduling with availability rules rather than group preference polling, Calendly is the correct integration to build.
Acuity Scheduling offers a REST API v1 with HTTP Basic auth (self-service credentials from Business Settings → Integrations → API) for service-based businesses that need appointment booking with intake forms, package management, and multi-calendar support. API access requires a paid Acuity plan. Better suited for client-facing appointment booking (salons, coaches, consultants) than group availability polling.
Notion's database API can be used to build a lightweight group scheduling poll using a Notion database with a date-column for time slots and a multi-select column for participants. This requires building a custom Notion Integration (simple token-based auth, self-service at notion.so/my-integrations). It is less purpose-built than a native Bubble poll but works for teams already using Notion as their primary workspace.
Frequently asked questions
Is there any way to access Doodle's API as an independent developer or small business?
As of 2026, Doodle's REST API v2 is restricted to enterprise partners. The API credential request form at developer.doodle.com requires enterprise partnership status. For independent developers, startups, and small Bubble apps, there is no standard self-service path to obtaining API credentials. The practical alternatives are the Doodle iframe embed or a custom Bubble scheduling poll, both covered in this tutorial. If Doodle's API access policy changes, check developer.doodle.com for updated requirements.
What are the limitations of embedding Doodle via iframe in Bubble?
The iframe embed gives you Doodle's scheduling UI inside your Bubble page, but Bubble has zero access to the data inside the iframe — no participant names, no votes, no results. You cannot trigger Bubble workflows when someone votes, query vote counts in a Bubble search, or store any scheduling data in Bubble's database. The poll's appearance uses Doodle's branding and layout (not your app's design). If Doodle changes its embed policy or URL structure, the embed breaks with no Bubble-side fix available. For any use case that requires data access, the custom Bubble poll is the correct path.
How do I prevent someone from voting multiple times in the custom Bubble poll?
Add a workflow condition as the first step of the voting submission workflow: search for SchedulingVotes where poll = current poll AND participant_email = the email input's value. If the count is greater than 0, show an error message ('You have already submitted your availability') and stop the workflow using Bubble's 'Terminate this workflow' step or an 'Only when count is 0' condition on the create action. This is an email-based check — for anonymous polls without email collection, you can use browser cookies via a JavaScript snippet (Toolbox plugin), though cookie-based duplicate prevention is easier to circumvent.
Can the custom Bubble poll send email notifications to participants?
Yes. After creating a SchedulingPoll, add a workflow action that calls your email provider's API (SendGrid, Mailgun, or Postmark via Bubble's API Connector) with the participant email addresses and the shareable voting link. You can also trigger a notification email to the organizer each time a new SchedulingVote is created — add this as the final action in the voting submission workflow. For scheduled reminders to participants who have not voted yet, you would need a Backend Workflow (paid Bubble plan) scheduled to run periodically and check for pending votes.
Should I use Doodle embed or build a custom poll if this is for a client-facing Bubble app?
For client-facing production apps, the custom Bubble poll is almost always the better choice. It keeps all data in your Bubble database (queryable, reportable, exportable), allows you to match your app's design exactly, gives you control over the user experience, and does not create a runtime dependency on Doodle's embed policy remaining unchanged. The iframe embed is appropriate for internal prototypes, MVP validation, or cases where Doodle's specific brand recognition matters to users and the scheduling data does not need to flow into other Bubble workflows.
What is the best use case for Doodle vs Calendly when building a Bubble app?
Doodle is designed for group availability polls — an organizer proposes several time options, multiple participants vote on which slots work for them, and the organizer picks the best one. It does not integrate with calendars or book appointments automatically. Calendly is designed for one-on-one or small-group booking with real calendar availability — it shows the organizer's available slots based on their calendar and books confirmed appointments automatically. In Bubble: Calendly has a real buildable API integration (OAuth 2.0, self-service); Doodle does not. Choose Doodle (via the embed or custom poll) for group preference gathering; choose Calendly for automated appointment booking.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation