Connect FlutterFlow to Vimeo in two parts: embed video playback using a WebView Custom Widget that loads the Vimeo player iframe, and manage your video library or analytics via the Vimeo REST API using a Firebase proxy. A Vimeo Pro account or higher is required to create API credentials — free Basic accounts cannot access the API. The personal access token or OAuth Bearer must never be embedded in the Flutter app bundle.
| Fact | Value |
|---|---|
| Tool | Vimeo |
| Category | Media & Content |
| Method | Custom Widget |
| Difficulty | Intermediate |
| Time required | 45 minutes |
| Last updated | July 2026 |
Embed Vimeo Videos and Manage Your Library in FlutterFlow
Most people building a Vimeo integration in FlutterFlow have two goals: play videos inside the app, and optionally browse or manage the video library. These are two separate systems in the Vimeo ecosystem, and it's worth understanding them separately before starting. Video playback is straightforward — every Vimeo video has a standard player embed URL at https://player.vimeo.com/video/{video_id}, and loading this URL in a WebView Custom Widget gives you the full Vimeo player experience (play/pause, fullscreen, quality selection) without any API credentials. The WebView approach works on both iOS and Android; the webview_flutter package is well-maintained and widely used for this pattern.
The API layer is where Vimeo adds its differentiating value and its key prerequisite: Vimeo Pro or higher. Free Basic accounts cannot create a developer app or generate an access token — this is a hard gating requirement, not a limitation that can be worked around. If your client or product requires Vimeo API access, budget for at least the Vimeo Pro plan before scoping the project. Once you have a paid account, the Vimeo Developer portal lets you create an app and generate a personal access token with scopes matching what your integration needs: public or private video access, interaction data for analytics, or video management for creating folders and setting privacy.
Vimeo's biggest differentiator over YouTube is its privacy control suite. Videos can be set to 'anybody' (public), 'unlisted' (share-link only), 'password' (viewer enters a passcode), 'disable' (no playback allowed), or 'domain' (only embeds on approved domains). The domain whitelist setting can break a WebView embed if the app's referrer isn't whitelisted in the video's privacy settings — this is one of the most common Vimeo FlutterFlow issues and worth checking during testing. The personal access token or OAuth Bearer token that unlocks the REST API is a secret credential that must never be embedded in the Flutter app bundle; route all authenticated API calls through a Firebase Cloud Function proxy.
Integration method
Vimeo integration in FlutterFlow uses two layers: a WebView Custom Widget (using the webview_flutter package) loads the Vimeo player embed URL for playback — this requires no API credentials since the player iframe is public. For library management and analytics (listing videos, reading privacy settings, view counts), a Firebase Cloud Function proxy holds the personal access token or OAuth Bearer and forwards authenticated REST calls to api.vimeo.com. FlutterFlow API Calls target the proxy, not Vimeo directly.
Prerequisites
- A Vimeo Pro, Business, or Premium account — free Basic accounts cannot create API apps or access tokens
- At least one video uploaded to Vimeo that you want to display in your FlutterFlow app
- A Firebase project on the Blaze plan to deploy Cloud Functions for the API proxy (required for library and analytics features)
- A FlutterFlow project with at least one screen for the video list or player
- Basic familiarity with FlutterFlow's Custom Code panel and API Calls
Step-by-step guide
Create a Vimeo API app and personal access token
Log in to developer.vimeo.com with your Vimeo Pro (or higher) account. Click 'Create an app' and fill in the app name, description, and app URL. Under 'What API scopes do you need?', select the scopes your integration requires: 'Public' for public video data, 'Private' to access unlisted or private videos, 'Video Files' if you need direct file URLs, 'Interact' for likes and comments, and 'Edit' or 'Upload' if you'll be managing or uploading videos. After creating the app, go to the 'Authentication' section and click 'Generate an Access Token.' Choose 'Authenticated (you)' for a personal token that accesses your account's videos, or 'OAuth 2.0' for a flow where your app's users can authorize with their own Vimeo accounts. Copy the generated personal access token immediately — it's only shown once in full and you'll need to regenerate if you miss it. Store it in your password manager. This token is your Vimeo API credential and goes into Firebase Secrets in the next step — it must never be placed in a FlutterFlow API Call header or in your app's source code. Also note your Vimeo user ID (the numeric ID visible in your profile URL or via the /me endpoint) — you'll use it to construct API endpoints for listing your videos.
Pro tip: Request the minimum scopes needed for your app. If you're only reading video metadata and view counts, 'Public' and 'Private' are sufficient. Adding 'Edit' or 'Upload' scopes when you don't need them increases the risk if the token is ever exposed.
Expected result: You have a Vimeo API app created with a personal access token copied and stored. The token is scoped with at least 'Public' access. You know your Vimeo user ID from your profile URL.
Build a WebView Custom Widget for Vimeo player embedding
The Vimeo player embed is the fastest path to video playback in FlutterFlow and requires no API credentials. The embed URL format is https://player.vimeo.com/video/{videoId}?autoplay=0&loop=0&color=ffffff — you can customize color (your brand hex), autoplay behavior, and loop via URL parameters. In FlutterFlow, go to Custom Code in the left nav → + Add → Widget. Name it 'VimeoPlayerWidget'. In the Dependencies field, add webview_flutter (check pub.dev for the current stable version). The widget takes two String parameters: videoId (the numeric Vimeo video ID) and optionally playerColor (hex string without #, e.g., '1ab7ea'). Paste the Dart code below. The widget builds the embed URL, loads it in a WebView, and sizes responsively to the parent container. After creating the widget, add it to your video detail screen. Set the videoId parameter from your video list item — either hardcoded for a single video or dynamically from your Vimeo API response. Set the height to approximately 56% of the screen width (16:9 aspect ratio) — use a Container with fixed height and set VimeoPlayerWidget to fill it. Custom Widgets do not render in FlutterFlow's web Test Mode — you must use Run mode or test on a real device to see the embedded player. Always test on the target platform (iOS and Android behave slightly differently with WebView content).
1import 'package:flutter/material.dart';2import 'package:webview_flutter/webview_flutter.dart';34class VimeoPlayerWidget extends StatefulWidget {5 const VimeoPlayerWidget({6 super.key,7 required this.videoId,8 this.playerColor = '1ab7ea',9 this.width,10 this.height,11 });1213 final String videoId;14 final String playerColor;15 final double? width;16 final double? height;1718 @override19 State<VimeoPlayerWidget> createState() => _VimeoPlayerWidgetState();20}2122class _VimeoPlayerWidgetState extends State<VimeoPlayerWidget> {23 late final WebViewController _controller;2425 @override26 void initState() {27 super.initState();28 final embedUrl =29 'https://player.vimeo.com/video/${widget.videoId}'30 '?autoplay=0&loop=0&color=${widget.playerColor}&byline=0&portrait=0';3132 _controller = WebViewController()33 ..setJavaScriptMode(JavaScriptMode.unrestricted)34 ..loadRequest(Uri.parse(embedUrl));35 }3637 @override38 Widget build(BuildContext context) {39 return SizedBox(40 width: widget.width ?? double.infinity,41 height: widget.height ?? 220,42 child: WebViewWidget(controller: _controller),43 );44 }45}Pro tip: Add ?dnt=1 (do not track) to the embed URL to disable Vimeo's tracking cookies — required for GDPR-compliant apps: https://player.vimeo.com/video/{id}?dnt=1. Vimeo may show an interstitial consent prompt to EU users without this parameter.
Expected result: The VimeoPlayerWidget appears in your Custom Widgets list. Adding it to a screen with a real Vimeo video ID shows the embedded Vimeo player with play controls on a real device or in Run mode.
Deploy a Firebase Cloud Function proxy for Vimeo REST API calls
For library management — listing your videos, reading view counts and privacy settings, or updating metadata — you need authenticated calls to the Vimeo REST API. These calls use your personal access token as a Bearer header and must be made from a server-side proxy, not from FlutterFlow directly. Store your Vimeo token as a Firebase Secret: firebase functions:secrets:set VIMEO_ACCESS_TOKEN. Deploy a Cloud Function (see the code snippet) that accepts a POST request from FlutterFlow with the Vimeo API endpoint path and optional query parameters, attaches the Authorization: bearer {token} header (note Vimeo uses lowercase 'bearer'), and forwards the request to https://api.vimeo.com. It returns the Vimeo API response directly to FlutterFlow. For library-heavy apps, also add a Firestore caching layer: the proxy can write video lists to Firestore after fetching them, and your FlutterFlow app reads the cached data for list screens. Use a scheduled Cloud Function to refresh the cache every few hours. This is also where video upload handling should live — Vimeo uses a resumable tus upload protocol that is complex for a mobile client. If your app needs video uploads, the Firebase proxy should handle the tus negotiation and upload entirely server-side. If this proxy setup feels like a lot to build, RapidDev's team implements FlutterFlow integrations with services like Vimeo every week — schedule a free scoping call at rapidevelopers.com/contact.
1// Firebase Cloud Function — Vimeo REST API proxy (Node.js)2const { onRequest } = require('firebase-functions/v2/https');3const { defineSecret } = require('firebase-functions/params');4const fetch = require('node-fetch');56const VIMEO_TOKEN = defineSecret('VIMEO_ACCESS_TOKEN');78exports.vimeoProxy = onRequest(9 { secrets: [VIMEO_TOKEN] },10 async (req, res) => {11 res.set('Access-Control-Allow-Origin', '*');12 if (req.method === 'OPTIONS') {13 res.set('Access-Control-Allow-Methods', 'POST');14 res.set('Access-Control-Allow-Headers', 'Content-Type');15 return res.status(204).send('');16 }1718 const { endpoint, queryParams, method, body } = req.body;19 const url = new URL(`https://api.vimeo.com${endpoint}`);2021 if (queryParams) {22 Object.entries(queryParams).forEach(([k, v]) =>23 url.searchParams.set(k, v)24 );25 }2627 const vimeoRes = await fetch(url.toString(), {28 method: method || 'GET',29 headers: {30 Authorization: `bearer ${VIMEO_TOKEN.value()}`,31 Accept: 'application/vnd.vimeo.*+json;version=3.4',32 'Content-Type': 'application/json',33 },34 body: body ? JSON.stringify(body) : undefined,35 });3637 const data = await vimeoRes.json();38 return res.status(vimeoRes.status).json(data);39 }40);Pro tip: Vimeo's API requires the Accept header with the versioned content type: application/vnd.vimeo.*+json;version=3.4. Omitting it causes some endpoints to return the wrong format or an error — include it in every proxy request.
Expected result: The vimeoProxy Cloud Function is deployed. Sending a POST with { endpoint: '/me/videos', queryParams: { per_page: '10' } } returns a JSON response containing your Vimeo video library.
Configure FlutterFlow API Calls for the Vimeo proxy and parse video data
In FlutterFlow, click API Calls in the left nav → + Add → Create API Group. Name it 'VimeoProxy' and set the Base URL to your Firebase Cloud Function URL. Add two primary API Calls: 1. 'List Videos' — POST with JSON body { endpoint: '/me/videos', queryParams: { per_page: '20', fields: 'uri,name,description,duration,pictures,stats,privacy' } }. The fields parameter limits the response to only the data you need, improving performance. In the Response & Test tab, paste a sample Vimeo /me/videos response and auto-generate JSON paths. Key paths: $.data[*].uri (full URI like /videos/123456), $.data[*].name, $.data[*].duration (seconds), $.data[*].pictures.sizes[0].link (thumbnail URL — use a larger size index like [3] or [4] for higher quality), $.data[*].stats.plays (view count), $.data[*].privacy.view (privacy setting string). Create a 'VimeoVideo' Data Type with these fields. 2. 'Get Video Detail' — POST with JSON body { endpoint: '/videos/{videoId}' (pass as a variable in the body or endpoint path) }. Parse the full video response including description, tags, and current privacy settings. For the video ID: extract it from the uri field by taking the last segment (e.g., /videos/123456 → 123456). Use a Custom Function in FlutterFlow to perform the string split: uri.split('/').last. Pass the extracted ID to your VimeoPlayerWidget as the videoId parameter.
1{2 "Group Name": "VimeoProxy",3 "Base URL": "https://us-central1-your-project.cloudfunctions.net/vimeoProxy",4 "Calls": [5 {6 "Name": "List Videos",7 "Method": "POST",8 "Body": {9 "endpoint": "/me/videos",10 "queryParams": {11 "per_page": "20",12 "fields": "uri,name,description,duration,pictures,stats,privacy"13 }14 },15 "JSON Paths": {16 "uri": "$.data[*].uri",17 "name": "$.data[*].name",18 "duration": "$.data[*].duration",19 "thumbnailUrl": "$.data[*].pictures.sizes[3].link",20 "viewCount": "$.data[*].stats.plays",21 "privacyView": "$.data[*].privacy.view"22 }23 },24 {25 "Name": "Get Video Detail",26 "Method": "POST",27 "Body": {28 "endpoint": "/videos/[variable:videoId]"29 },30 "JSON Paths": {31 "name": "$.name",32 "description": "$.description",33 "duration": "$.duration",34 "privacyView": "$.privacy.view",35 "privacyDomain": "$.privacy.domains"36 }37 }38 ]39}Pro tip: Use the fields query parameter in every Vimeo API request to limit the response payload. Vimeo's full video objects can be large — requesting only the fields you need significantly reduces response size and speeds up your FlutterFlow API Calls.
Expected result: The VimeoProxy group has 'List Videos' and 'Get Video Detail' calls. Testing 'List Videos' returns an array of video objects with names, thumbnail URLs, durations, and view counts from your Vimeo account.
Build the video library screen and connect it to the player
With the API Calls configured and the VimeoPlayerWidget ready, build the complete video library experience in FlutterFlow. Add a screen called 'Video Library' with a ListView that loads videos on page load using the 'List Videos' API Call. Store the result in a Page State variable videoList (list of VimeoVideo Data Type). For each ListView item, add a Card containing: a Network Image widget bound to VimeoVideo.thumbnailUrl; a duration badge (convert seconds to MM:SS using a Custom Function: '${(dur ~/ 60).toString().padLeft(2, '0')}:${(dur % 60).toString().padLeft(2, '0')}'); the video name in a bold Text widget; and a Text chip showing the privacy view setting (e.g., 'anybody', 'unlisted', 'password') so admins can see content access at a glance. On tap, navigate to a 'Video Player' screen. Pass the video ID (extracted from the uri field) and the video name as navigation parameters. On the Video Player screen, add the VimeoPlayerWidget at the top with the videoId parameter bound to the navigation-passed ID. Below it, show title, description, and view count (fetched on-screen-open via 'Get Video Detail'). Add a Pull to Refresh on the library screen that re-calls 'List Videos' and updates the page state. Note: the VimeoPlayerWidget requires testing in Run mode on a real device — it will appear as a grey box in web Test Mode preview.
Pro tip: Create a Custom Function that extracts the video ID from a Vimeo URI string: String extractVimeoId(String uri) { return uri.split('/').last; } — use this function in your ListView item's On Tap action to pass the correct video ID to the player screen.
Expected result: The Video Library screen loads a list of Vimeo videos with thumbnails, durations, and privacy badges. Tapping a video navigates to the player screen and the embedded Vimeo player shows the video on device.
Common use cases
Course platform app with gated Vimeo video lessons
A FlutterFlow learning app where enrolled students watch course video lessons hosted privately on Vimeo. Each lesson page shows the title, description, and duration fetched from the Vimeo API via proxy, and the WebView widget embeds the Vimeo player for the video. Privacy is managed in Vimeo (unlisted URLs) so only app users with the lesson link can view the content.
Build a FlutterFlow course player app that shows a list of lesson videos from Vimeo with titles and durations, and plays each lesson in an embedded Vimeo player when tapped.
Copy this prompt to try it in FlutterFlow
Video portfolio app for a creative agency
A FlutterFlow portfolio app that showcases a creative agency's Vimeo video work. The app fetches the agency's Vimeo library via the API proxy, displays video thumbnails, titles, and view counts in a grid, and plays the selected video in a WebView embed. The team can update the portfolio by uploading new videos to Vimeo without touching the FlutterFlow app.
Create a FlutterFlow portfolio gallery that pulls all videos from a Vimeo account, shows thumbnail and view count for each, and plays the video in an embedded player when tapped.
Copy this prompt to try it in FlutterFlow
Internal video library for a company's training content
A FlutterFlow internal app for company employees to browse and watch training videos hosted on a private Vimeo account. The app uses the Vimeo API to list videos from a specific folder, show their privacy status, and the WebView embed handles playback. Privacy settings ensure only authorized employees can access the content via the app.
Build a FlutterFlow internal training app that lists videos from a Vimeo folder organized by department, shows the video length and privacy status, and plays training content in an embedded Vimeo player.
Copy this prompt to try it in FlutterFlow
Troubleshooting
The embedded Vimeo player shows a blank screen or 'This video is private' error in the WebView
Cause: The video's privacy setting is set to 'domain' (domain-whitelisted) and the WebView referrer is not on the approved domain list, or the video is set to 'password' or 'disable' which blocks all embeds.
Solution: In Vimeo, go to the video settings → Privacy tab. If it's set to 'domain', your app's domain (or 'localhost' for development) must be in the whitelist. For mobile apps, the WebView doesn't send a standard web domain referrer — set the privacy to 'anybody' or 'unlisted' for mobile app embedding, or use the Vimeo API to set privacy to allow embeds on any domain. Check the video's privacy.embed and privacy.view settings via the Get Video Detail API Call.
Vimeo API returns 403 Forbidden or 'You do not have access to this endpoint' with a personal access token
Cause: The personal access token was generated without the required scope for the endpoint being called, or the Vimeo account is a Basic (free) account which cannot create API tokens.
Solution: In developer.vimeo.com, go to your app, delete the existing personal access token, and regenerate it with the correct scopes checked (add 'Private' for private video access, 'Interact' for stats, 'Edit' for metadata updates). Confirm your Vimeo account is Pro, Business, or Premium — Basic accounts cannot generate personal access tokens and will see 403 errors.
VimeoPlayerWidget appears as a grey box or doesn't render in FlutterFlow
Cause: Custom Widgets using native packages like webview_flutter do not render in FlutterFlow's in-browser Test Mode preview canvas.
Solution: Switch to FlutterFlow's Run mode to test on a real iOS or Android device. The VimeoPlayerWidget will display correctly on actual devices. For web builds, note that webview_flutter has web support but may behave differently — test web builds separately from mobile builds.
API Call to list videos returns an empty data array even though videos exist in the Vimeo account
Cause: The personal access token was generated for a different Vimeo account, the token lacks the 'Private' scope needed to see non-public videos, or the /me/videos endpoint is returning filtered results because the fields parameter excluded the privacy-gated items.
Solution: Verify the token is for the correct Vimeo account by testing /me via the proxy — the response should show your account username and email. Add the 'Private' scope to your token if any videos are non-public. Remove the fields parameter temporarily to see the full response and confirm the videos are present in the raw data.
Best practices
- Confirm your Vimeo account is Pro or higher before starting development — free Basic accounts cannot create API credentials, making this a hard prerequisite.
- Never place the Vimeo personal access token or OAuth Bearer in a FlutterFlow API Call header — proxy all authenticated REST calls through Firebase Cloud Functions.
- Use the ?fields= query parameter in every Vimeo API request to limit response payload to only the fields your app needs — Vimeo video objects are verbose and large.
- Test the VimeoPlayerWidget on a real device or in Run mode — Custom Widgets do not render in FlutterFlow's web-based Test Mode preview.
- Add ?dnt=1 to all Vimeo embed URLs for GDPR compliance — it disables Vimeo's tracking cookies and prevents cookie consent prompts from appearing in the WebView.
- Check the privacy.view and privacy.embed settings of each video via the API before displaying an embed — domain-restricted videos will show a blank player if the app's WebView referrer isn't whitelisted.
- Handle video uploads via the Firebase Cloud Function proxy using Vimeo's tus resumable upload protocol — mobile clients should not perform large file uploads directly.
- Cache video library listings in Firestore for gallery screens and reload on pull-to-refresh rather than auto-fetching on every screen navigation — reduces API calls and speeds up load time.
Alternatives
Choose YouTube if you need open API access without a paid account requirement and are comfortable with the 10,000-unit-per-day quota model and public-facing video content.
Choose WordPress if your content is primarily written posts and pages rather than video — or if you're using WordPress with a video plugin to host media alongside text content.
Choose Spotify if your app's primary media type is audio tracks and playlists rather than video content with privacy controls.
Frequently asked questions
Can I use Vimeo's free Basic account to build a FlutterFlow app with embedded videos?
You can embed videos (using the WebView Custom Widget with the player URL) without API credentials — any Vimeo account level can use the embed URL. However, if you need to list videos programmatically, access analytics, or manage privacy settings via the Vimeo REST API, you need at least a Vimeo Pro account to create an API app and generate access tokens. Free Basic accounts cannot access the developer API.
Does the Vimeo player embed work on both iOS and Android in FlutterFlow?
Yes. The webview_flutter package supports both iOS and Android. The VimeoPlayerWidget will display the Vimeo player with play, pause, and fullscreen controls on both platforms. Note that it will not render in FlutterFlow's in-browser Test Mode — always test using Run mode on a real device or emulator. For Flutter web builds, webview_flutter also has web support, but test this build target separately as behavior can differ from native mobile.
How do I show only specific Vimeo videos in my FlutterFlow app (not my entire library)?
Vimeo organizes videos into folders (formerly 'albums' or 'showcases') and projects. Use the API endpoint /me/projects/{project_id}/videos to list only the videos in a specific folder. Alternatively, use /videos/{id} for individual video lookups by ID. You can also filter by tag using the Vimeo search endpoint with a query parameter. Configure the proxy endpoint call in FlutterFlow to target the folder-specific endpoint rather than /me/videos for curated collections.
Can users of my FlutterFlow app upload their own videos to Vimeo through the app?
Technically yes, but it's complex. Vimeo uses a tus resumable upload protocol that involves a multi-step process: create an upload slot via the API, perform a chunked tus upload to the returned URL, and optionally set metadata after completion. This should be handled entirely in the Firebase Cloud Function proxy — not on the mobile device — due to the complexity, potential for large files, and the need for the API token. This is an advanced use case beyond a standard integration; weigh whether Vimeo upload is the right approach or if direct upload to Vimeo's web interface fits better.
Will Vimeo's domain-restricted privacy settings block my FlutterFlow app's WebView?
Yes, potentially. When you set a Vimeo video to 'domain' privacy and specify allowed domains, the Vimeo player checks the referring domain before allowing playback. Mobile app WebViews often don't send a standard web domain referrer, so Vimeo may block the embed. The safest approach for mobile apps is to use 'unlisted' privacy (share-link only, no domain restriction) rather than domain whitelisting. Check your video's privacy settings in Vimeo's settings panel and test the embed in your actual app, not just a browser.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation