Skip to main content
RapidDev - Software Development Agency
flutterflow-integrationsFlutterFlow API Call

Calendly

Connect FlutterFlow to Calendly using two approaches: embed your Calendly scheduling page in a WebView widget for instant booking with zero backend, or call the Calendly v2 REST API through a Firebase Cloud Function proxy to read booked events into a native list. The Personal Access Token must never live in a FlutterFlow API Call — it ships in the compiled app bundle and is trivially extractable.

What you'll learn

  • How to embed a Calendly booking page in a FlutterFlow WebView widget for instant scheduling
  • Why the Calendly Personal Access Token must be proxied through a Firebase Cloud Function
  • How to create an API Group in FlutterFlow targeting your Cloud Function
  • How to map scheduled_events JSON into a Custom Data Type and ListView
  • How to implement pull-to-refresh for free-plan users who cannot use Calendly webhooks
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate15 min read45 minutesProductivityLast updated July 2026RapidDev Engineering Team
TL;DR

Connect FlutterFlow to Calendly using two approaches: embed your Calendly scheduling page in a WebView widget for instant booking with zero backend, or call the Calendly v2 REST API through a Firebase Cloud Function proxy to read booked events into a native list. The Personal Access Token must never live in a FlutterFlow API Call — it ships in the compiled app bundle and is trivially extractable.

Quick facts about this guide
FactValue
ToolCalendly
CategoryProductivity
MethodFlutterFlow API Call
DifficultyIntermediate
Time required45 minutes
Last updatedJuly 2026

Two Ways to Use Calendly in a FlutterFlow App

Calendly is one of the most popular scheduling tools for founders, consultants, and SaaS products — and adding it to a FlutterFlow app unlocks two very different features. The quickest win is embedding your Calendly scheduling page directly inside the app using a WebView widget. Your users tap a button, a full-screen WebView opens at your `calendly.com/you/meeting-type` URL, and they book a slot without you writing a single line of API code. This works on day one, requires no credentials, and gives you Calendly's full booking experience inside your native shell.

The second path is more powerful: calling the Calendly v2 REST API to pull booked events into a native FlutterFlow screen. Endpoints like `GET /scheduled_events` and `GET /scheduled_events/{uuid}/invitees` return structured JSON you can bind to a ListView — great for coach apps, service businesses, or dashboards where users need to see upcoming appointments inside the app itself. Calendly's free plan covers these read endpoints with no per-call charge.

The critical constraint for FlutterFlow: the Personal Access Token (PAT) that authenticates Calendly API calls is a long-lived static credential that grants access to your entire Calendly account. Because FlutterFlow compiles to a client-side Flutter app, any token placed in an API Call header is embedded in the app bundle and can be extracted. The solution is a Firebase Cloud Function (or Supabase Edge Function) that holds the PAT as a server-side environment variable and proxies requests to Calendly — your FlutterFlow app calls the function URL, and the function forwards the call with the correct `Authorization: Bearer` header. Note that webhooks (real-time booking notifications) require Calendly's Standard plan at $10/user/month or higher; on the free plan, poll on screen load or pull-to-refresh instead.

Integration method

FlutterFlow API Call

Calendly offers two honest paths for FlutterFlow. The fastest is a WebView widget pointing at your public Calendly link — no API Group, no credentials, works immediately. The data path uses the Calendly v2 REST API (base URL: https://api.calendly.com) to pull scheduled events into a native list, but requires a Firebase Cloud Function proxy to hold the Personal Access Token safely. FlutterFlow's API Calls panel then targets the function URL rather than Calendly directly.

Prerequisites

  • A Calendly account (free plan works for the WebView embed and API read endpoints)
  • A FlutterFlow project open in your browser
  • A Firebase project with Cloud Functions enabled (for the API data path)
  • Your Calendly Personal Access Token from app.calendly.com/integrations/api_webhooks (for the API path)
  • Familiarity with the FlutterFlow API Calls panel and Action Flow Editor

Step-by-step guide

1

Step 1: Embed your Calendly booking page with a WebView widget (fastest path)

The quickest way to add Calendly to your FlutterFlow app is embedding the scheduling page in a WebView widget — no API Group, no Cloud Function, no credentials. In FlutterFlow, open the page where you want booking to appear. In the widget tree, click the + icon to add a widget, search for 'WebView', and drop it onto your canvas. In the WebView properties panel on the right, set the 'Content Type' to 'URL' and paste your Calendly link in the URL field — for example, `https://calendly.com/your-name/30min`. You can also make this dynamic by creating a page parameter called `bookingUrl` and binding the WebView URL to that parameter, so the same screen works for multiple meeting types or multiple team members. If you want booking to open in a full-screen overlay rather than an embedded panel, use the 'Launch URL' action instead: wire a button's On Tap action to Action Flow Editor → + Add Action → Utilities → Launch URL, then set the URL to your Calendly link. On mobile, this opens the device browser or the Calendly app if installed. Important limitation: the WebView embed is online-only (no offline fallback) and cannot pass booking data back into your FlutterFlow app state — you cannot read who just booked from the WebView itself. If you need post-booking confirmation inside the app, you'll need the API path in Steps 2–5.

Pro tip: Use a full-screen WebView on a dedicated route (e.g., /book) rather than embedding it in a small panel — the Calendly scheduling UI is designed for a full viewport and looks cramped in a small container.

Expected result: A WebView widget on your canvas showing a preview of your Calendly scheduling page. On a real device, users can complete the full booking flow without leaving the app.

2

Step 2: Get your Calendly Personal Access Token and deploy a Cloud Function proxy

For the data-sync path — reading scheduled events into a native FlutterFlow list — you need the Calendly v2 REST API. Start by getting a Personal Access Token (PAT): log in to Calendly, go to app.calendly.com/integrations/api_webhooks, click 'Personal Access Tokens', then 'Create new token'. Name it (e.g., 'FlutterFlow App'), copy the token immediately — you won't see it again. Now, the critical security step: this PAT must not go into a FlutterFlow API Call header, because FlutterFlow compiles to a client-side Flutter app and the header value ships inside the app bundle. Anyone who downloads your app can extract it with standard reverse-engineering tools and access your Calendly account. The solution is a Firebase Cloud Function that holds the PAT as a server-side environment variable and acts as a proxy. In your Firebase project console, go to Cloud Functions → click 'Get started' if not already enabled. You'll write a simple HTTP-triggered function that receives a request from FlutterFlow, adds the Authorization header with your PAT, calls the Calendly API, and returns the response. Deploy this function and note its HTTPS trigger URL — this is what FlutterFlow will call, not Calendly directly. Set your PAT as a Cloud Function environment variable using `firebase functions:config:set calendly.token="YOUR_PAT"` in the Firebase CLI (this keeps the token out of version control and out of the app bundle entirely).

index.js
1// Firebase Cloud Function proxy for Calendly v2 API
2// index.js — deploy with: firebase deploy --only functions
3const functions = require('firebase-functions');
4const https = require('https');
5
6exports.calendlyProxy = functions.https.onRequest((req, res) => {
7 // Allow FlutterFlow web target (CORS)
8 res.set('Access-Control-Allow-Origin', '*');
9 res.set('Access-Control-Allow-Methods', 'GET, OPTIONS');
10 res.set('Access-Control-Allow-Headers', 'Content-Type');
11 if (req.method === 'OPTIONS') { res.status(204).send(''); return; }
12
13 const token = functions.config().calendly.token;
14 const path = req.query.path || '/users/me';
15
16 const options = {
17 hostname: 'api.calendly.com',
18 path: path,
19 method: 'GET',
20 headers: {
21 'Authorization': `Bearer ${token}`,
22 'Content-Type': 'application/json'
23 }
24 };
25
26 const proxyReq = https.request(options, (proxyRes) => {
27 let data = '';
28 proxyRes.on('data', chunk => { data += chunk; });
29 proxyRes.on('end', () => {
30 res.status(proxyRes.statusCode).json(JSON.parse(data));
31 });
32 });
33 proxyReq.on('error', (e) => { res.status(500).json({ error: e.message }); });
34 proxyReq.end();
35});

Pro tip: Set your PAT via Firebase CLI config (firebase functions:config:set) so it's never in your source code. The function reads it at runtime with functions.config().calendly.token.

Expected result: A deployed Cloud Function with an HTTPS trigger URL (e.g., https://us-central1-your-project.cloudfunctions.net/calendlyProxy). You can test it in a browser by appending ?path=/users/me to the URL and checking that it returns your Calendly user JSON.

3

Step 3: Create a FlutterFlow API Group targeting your Cloud Function

Now wire FlutterFlow to your Cloud Function proxy. In the left navigation panel of FlutterFlow, click 'API Calls'. Click '+ Add' and choose 'Create API Group'. Name the group 'Calendly', set the Base URL to your Cloud Function's HTTPS trigger URL (e.g., `https://us-central1-your-project.cloudfunctions.net/calendlyProxy`). You do not need any shared group-level headers here because the Cloud Function handles the Calendly authorization internally — the token never touches the FlutterFlow side. Next, click '+ Add API Call' inside the Calendly group. Name this call 'Get Scheduled Events'. Set the Method to GET. In the Variables tab, add a variable called `path` with a default value of `?path=/scheduled_events`. This lets the proxy know which Calendly endpoint to forward to. In the API Call URL field, append `{{ path }}` so the full URL becomes your function URL plus the path variable. Now click 'Response & Test'. Add a sample Calendly scheduled_events response in the Response Body field — you can get this by running the Cloud Function in your browser. Click 'Generate JSON Paths' and FlutterFlow will analyze the JSON and suggest bindable paths like `$.collection[*].name.text`, `$.collection[*].start_time`, `$.collection[*].status`. These JSON paths are how FlutterFlow reads individual fields out of the API response to bind to widgets.

Pro tip: Create separate API Calls within the same group for each Calendly endpoint you need — one for /scheduled_events, one for /scheduled_events/{uuid}/invitees. Pass the specific path as a variable so the proxy routes correctly.

Expected result: An API Group named 'Calendly' appears in the API Calls panel with a 'Get Scheduled Events' call inside it. Running the test returns a 200 response with event JSON from Calendly.

4

Step 4: Map events JSON to a Custom Data Type and bind to a ListView

To display scheduled events in a native FlutterFlow list, you need to define a Custom Data Type that matches the fields you care about from the Calendly response. Go to Settings → Data Types → + Add Data Type. Name it 'CalendlyEvent'. Add fields: `eventName` (String), `startTime` (String), `status` (String), `inviteeName` (String). These map to Calendly's JSON structure under `collection[*]`. Now go to your screen in FlutterFlow. Add a ListView widget to the canvas. In the ListView's Backend Query section (on the right panel), select 'API Call' as the query type and pick your 'Get Scheduled Events' call. FlutterFlow will display the available JSON paths from your earlier test. Map `$.collection[*].name.text` to `eventName`, `$.collection[*].start_time` to `startTime`, and `$.collection[*].status` to `status`. Inside the ListView, add a Card widget as the list item. Inside the card, add Text widgets for the event name and start time. Bind each Text widget's value to the corresponding field on the CalendlyEvent Data Type — in the widget's properties panel, click the orange binding icon next to the value field and select the list item's field. Add conditional visibility to show a status badge only when `status == 'active'`. Your ListView will now populate with real Calendly events when the screen loads, fetched through your Cloud Function proxy. For the invitee name, add a second API Call named 'Get Invitees' that passes the event UUID — get the UUID from `$.collection[*].uri` split on the last slash. Make this a separate call triggered from the card's On Tap action, showing invitee details on a new screen.

Pro tip: Calendly returns start_time as an ISO 8601 string (e.g., '2026-03-15T14:00:00.000000Z'). Use FlutterFlow's date formatting options in the Text widget binding to display it in a human-readable format.

Expected result: A ListView on your screen populated with upcoming Calendly events, each showing the meeting name, start time, and a status badge. The list loads when the screen opens.

5

Step 5: Add pull-to-refresh (free plan workaround for no webhooks)

Calendly's free plan does not support webhooks — there's no push notification when a new booking is made. The paid Standard plan ($10/user/month) adds webhook support, but webhooks also require a backend to receive them (a Cloud Function endpoint), which FlutterFlow cannot host natively. For most founders, the practical solution on the free plan is polling: refresh the events list when the user opens the screen, and add a pull-to-refresh gesture so they can manually refresh. To add pull-to-refresh in FlutterFlow, select your ListView widget and look for the 'Pull to Refresh' toggle in the properties panel — enable it. Then set the action that fires on refresh: open the Action Flow Editor for the ListView's On Pull to Refresh event, add a 'Refresh Page' or 'Re-trigger Backend Query' action. This forces the ListView to re-execute the API Call and fetch the latest events from Calendly. If you do upgrade to a paid Calendly plan and want real-time updates: set up a Calendly webhook subscription (via API: POST /webhook_subscriptions) pointing at a new Cloud Function endpoint. That function receives the booking event, writes it to your Firestore database, and your FlutterFlow app reads from Firestore in real time using FlutterFlow's native Firebase integration. This is the proper architecture for live booking notifications — Calendly pushes to Cloud Function, function writes to Firestore, app subscribes to Firestore stream. For the RapidDev note: if you're building a booking-heavy app and want the full real-time webhook architecture set up correctly, RapidDev's team builds FlutterFlow integrations like this every week — free scoping call at rapidevelopers.com/contact.

Pro tip: Cache the last-fetched events list in App State so the screen shows stale data instantly while the API call refreshes in the background — this prevents the blank-screen flash on every load.

Expected result: The ListView refreshes and shows the latest Calendly bookings when the user pulls down. A loading indicator appears during the refresh and disappears when the new data arrives.

Common use cases

Coaching app with in-app session booking

A 1:1 coaching app where clients browse service packages on a native screen, then tap 'Book a Session' to open the coach's Calendly page in a full-screen WebView. After booking, the confirmation stays in Calendly's email flow — no payment or calendar logic needed in the app.

FlutterFlow Prompt

Build a coaching services screen with a list of session types (30-min intro, 60-min deep dive) and a 'Book Now' button that opens my Calendly link in a WebView.

Copy this prompt to try it in FlutterFlow

Dashboard showing upcoming client appointments

A consultant's FlutterFlow admin app that displays all upcoming scheduled events pulled from the Calendly v2 API — showing event name, start time, and invitee name in a card list. The list refreshes on pull-to-refresh since the free plan has no webhooks.

FlutterFlow Prompt

Create an Upcoming Appointments screen that shows all my Calendly bookings for the next 7 days in a card list with the client name, meeting type, and start time.

Copy this prompt to try it in FlutterFlow

Service marketplace with per-provider booking links

A marketplace app where each service provider has a profile card with their own Calendly link. Tapping 'Schedule a Call' opens that provider's Calendly page in a WebView, keeping the booking experience inside the app rather than switching to a browser.

FlutterFlow Prompt

Add a 'Schedule a Call' button to each expert profile card in my marketplace app that opens their specific Calendly booking link in a WebView overlay.

Copy this prompt to try it in FlutterFlow

Troubleshooting

401 Unauthorized when calling the Cloud Function — Calendly returns 'Could not authenticate you'

Cause: The PAT set in Firebase Functions config is missing, incorrectly set, or the function wasn't redeployed after setting the config variable.

Solution: Run `firebase functions:config:get` to verify the token value is present. If missing, run `firebase functions:config:set calendly.token="your-token"` again and then `firebase deploy --only functions` to redeploy. The function only picks up config changes after a fresh deploy.

XMLHttpRequest error in FlutterFlow Test Mode — the API Call fails in the browser but works on a device

Cause: This is a CORS error. The browser enforces CORS; native iOS/Android builds do not. If you're calling Calendly directly (without the proxy), the Calendly API blocks browser origins. Even with the proxy, the Cloud Function itself must return CORS headers.

Solution: Ensure your Cloud Function sets 'Access-Control-Allow-Origin: *' in the response headers and handles OPTIONS preflight requests (returning 204). The example proxy code in Step 2 includes this. Test Mode runs in a browser so CORS is enforced there — if the proxy is correctly configured, it will work in both Test Mode and on device.

Events list is empty even though bookings exist in Calendly

Cause: The /scheduled_events endpoint returns events in a time window. By default it may return only future events, or require a max_start_time/min_start_time parameter. A wrong organization URI can also cause empty results.

Solution: First call GET /users/me through your proxy to get your user URI (looks like https://api.calendly.com/users/abc123). Then call /scheduled_events?user={uri}&min_start_time={ISO8601}&max_start_time={ISO8601} with the correct user URI and a time range. Pass these as query parameters through your proxy's path variable.

WebView booking page does not load — shows a blank screen or 'Page not found'

Cause: The Calendly URL is malformed (wrong username or meeting-type slug), or the device has no internet connection. On the web target, an iframe security policy on Calendly's side can also block embedding.

Solution: Double-check the URL format: it must be https://calendly.com/your-username/your-event-type exactly as shown on your Calendly dashboard. Test the URL in a regular browser first. For the web build where iframes may be blocked, use the 'Launch URL' action to open in a new tab instead of embedding in a WebView.

Best practices

  • Never put your Calendly Personal Access Token in a FlutterFlow API Call header — it ships in the compiled app bundle and is extractable. Always route it through a Firebase Cloud Function.
  • Start with the WebView embed for the booking flow — it works immediately, requires no credentials, and gives users the full Calendly scheduling experience including confirmation emails.
  • Use the 'Launch URL' action instead of an embedded WebView for the web build target, where iframe embedding may be blocked by Calendly's content security policy.
  • Poll on screen load rather than expecting webhook push events on the free plan — webhooks require the Standard plan ($10/user/month) and a Cloud Function to receive them.
  • Cache the events list in App State so the screen doesn't flash blank on every load — show cached data immediately, then update it when the API call completes.
  • Use separate API Calls within the same API Group for /scheduled_events and /scheduled_events/{uuid}/invitees — pass the endpoint path as a variable to your proxy rather than hardcoding it.
  • For OAuth (multi-user Calendly): don't attempt OAuth inside FlutterFlow — implement the full OAuth 2.0 exchange in a Cloud Function and store the per-user access token in Firestore keyed to the user's UID.

Alternatives

Frequently asked questions

Can I show a Calendly booking form inside my FlutterFlow app without a WebView?

Not natively. Calendly's scheduling UI is a hosted web experience — there's no official Flutter widget or embeddable component. The WebView widget is the correct way to show the Calendly scheduling page inside a FlutterFlow app. If you need a fully native booking form, you'd have to build one from scratch and use the Calendly API to create scheduled events, which requires the paid plan and a complex integration.

Does Calendly's free plan work with FlutterFlow?

Yes — the free plan supports the WebView embed (no API needed) and allows read access to the v2 REST API endpoints like /scheduled_events and /users/me. The limitation is that the free plan has no webhook support, so you cannot receive real-time booking notifications. You'll need to poll on screen load or use pull-to-refresh to get the latest events.

Why can't I just put the Calendly PAT in an App Value or App State variable in FlutterFlow?

App Values and App State are stored client-side in the compiled Flutter app — they're accessible in the device's memory and can be extracted. Any secret placed there is as exposed as a hardcoded string. The only safe storage for a secret token is a server-side environment variable inside a Cloud Function or Edge Function, where the client never sees the raw value.

How do I handle multiple team members each with their own Calendly link?

Store each team member's Calendly URL (the public booking link, not any private token) in your Firestore or Supabase database alongside their user profile. When a user taps a team member's card, fetch their Calendly URL from the database and pass it as a parameter to your booking screen, which opens the WebView with that specific URL. This requires no secrets — the public booking URL is safe to store client-side.

Can FlutterFlow receive a notification when someone books a meeting?

Yes, but it requires both a paid Calendly plan (Standard, $10/user/month) and a backend receiver. Set up a Calendly webhook subscription via the API pointing at a Firebase Cloud Function endpoint. When Calendly fires the webhook on booking, the function writes the new event to Firestore. Your FlutterFlow app subscribes to the Firestore document in real time using FlutterFlow's native Firebase integration, triggering a notification or updating the UI automatically.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Integrations are where projects stall

We wire FlutterFlow integrations like this one every week — auth, webhooks, edge cases included. Fixed-price builds from $13K, delivered in 6–10 weeks.

Talk to an integration engineer

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.