GitLab has a comprehensive REST API v4 at https://gitlab.com/api/v4/ with Personal Access Token auth (PRIVATE-TOKEN header). Connect Bubble to GitLab to build internal dev dashboards showing pipeline status, open issues, and merge requests — or trigger pipeline runs from a Bubble button. Unlike GitHub, GitLab bundles CI/CD natively, making one API give you the full DevOps picture. Inbound GitLab webhooks require a paid Bubble plan.
| Fact | Value |
|---|---|
| Tool | GitLab |
| Category | DevOps & Tools |
| Method | Bubble API Connector |
| Difficulty | Intermediate |
| Time required | 40–55 minutes |
| Last updated | July 2026 |
Build a GitLab DevOps dashboard in Bubble — no premium plan required
The most practical Bubble + GitLab use-case is an internal dev dashboard: a Bubble page that shows your team's GitLab pipeline health, open issues, and merge request status — all without team members needing to log into GitLab. Product managers, QA leads, and client stakeholders can monitor development progress in a clean Bubble interface that surfaces only the data they care about.
GitLab's key advantage over GitHub for this use-case: CI/CD pipelines are built-in at every pricing tier. A single GitLab API call gives you pipeline status, job names, and deployment environment info — data that on GitHub would require separate GitHub Actions API calls and a paid tier for some features. The result is that a Bubble dashboard built on GitLab's API can show a more complete DevOps picture with fewer API calls.
GitLab uses a unique `PRIVATE-TOKEN` header for authentication (rather than the `Authorization: Bearer` pattern used by most other services). This is the #1 gotcha for developers used to other API integrations — using 'Authorization' instead of 'PRIVATE-TOKEN' will result in 401 errors on all calls.
Integration method
Bubble's API Connector calls the GitLab REST API v4 server-side using a PRIVATE-TOKEN header marked Private, so your GitLab credentials never reach the browser. No CORS issues since all calls are server-to-server.
Prerequisites
- A GitLab account (free — GitLab's API is accessible on all tiers including Free)
- At least one GitLab project with some pipelines or issues to test with during initialization
- The numeric project ID for your GitLab project (found in the project's main page under the project name, or in Settings → General)
- A Bubble account — any plan works for outbound API calls; a paid Bubble plan is required for inbound GitLab webhooks via Backend Workflows
Step-by-step guide
Create a GitLab Personal Access Token with API scope
GitLab Personal Access Tokens are the simplest auth method for Bubble integrations. They're generated in your GitLab user settings and can be scoped to specific permissions. Log in to your GitLab account at gitlab.com. Click your profile avatar in the top-right corner and select 'Edit profile' from the dropdown. In the left sidebar, click 'Access Tokens'. Click 'Add new token'. Fill in the token form: - Token name: 'Bubble Dashboard Integration' (something descriptive) - Expiration date: Set an appropriate expiry date (GitLab now requires an expiry on all tokens for security). A 1-year expiry is common for long-lived integrations; set a reminder to rotate the token before it expires. - Select scopes: check 'api' for full read/write API access. If you only need a read-only dashboard, check 'read_api' instead — this is safer for display-only Bubble apps. Click 'Create personal access token'. The token is displayed ONCE — copy it immediately and store it somewhere safe (a password manager). GitLab will never show this token again. For production Bubble apps with multiple users or organizational use, consider a Project Access Token (GitLab Premium) which is scoped to a single project rather than your entire account. For free-tier GitLab, Personal Access Tokens are the available option.
Pro tip: Choose 'read_api' scope instead of 'api' if your Bubble dashboard is read-only (displaying pipelines and issues without triggering pipelines or creating issues). The principle of least privilege reduces risk if the token is compromised.
Expected result: You have a GitLab Personal Access Token with the appropriate scope copied and ready to paste into Bubble. The token is stored securely.
Configure the Bubble API Connector with GitLab base URL and PRIVATE-TOKEN header
Open your Bubble app editor. Click the Plugins tab in the left sidebar. If the API Connector is not installed, click Add plugins, search for 'API Connector' (by Bubble), and install it. Return to Plugins → API Connector. Click Add another API. Set the name to 'GitLab'. In the Shared headers section, click Add a shared header: - Key: `PRIVATE-TOKEN` - Value: paste your GitLab Personal Access Token - Check the 'Private' checkbox on this header This is the critical difference from most other API integrations: GitLab uses `PRIVATE-TOKEN` as the header name — not `Authorization: Bearer`. Using `Authorization` will result in 401 Unauthorized responses on all calls. Base URL for calls: `https://gitlab.com/api/v4` If you're using a self-hosted GitLab instance (GitLab installed on your own server), the base URL is different: `https://{your-gitlab-host}/api/v4`. For example, if your company's GitLab is at gitlab.yourcompany.com, the base URL is https://gitlab.yourcompany.com/api/v4. Add a second optional non-private header: - Key: `Content-Type` - Value: `application/json` Save the API group configuration.
1{2 "API Name": "GitLab",3 "Shared Headers": {4 "PRIVATE-TOKEN": "<private>",5 "Content-Type": "application/json"6 },7 "Base URL": "https://gitlab.com/api/v4"8}Pro tip: The header must be 'PRIVATE-TOKEN' in all caps with a hyphen, exactly as shown. GitLab's API is case-sensitive on header names in some configurations — use the exact casing shown in GitLab's API documentation.
Expected result: The GitLab API group is configured in Bubble with a Private PRIVATE-TOKEN header. No calls added yet.
Add API calls for pipelines, issues, and merge requests, then initialize
Add GET calls for the three core data types you'll display in the Bubble dashboard. You'll need your GitLab project's numeric ID — find it in your GitLab project under Settings → General → Project ID (shown below the project name). Call 1 — Get Pipelines: - Click Add another call in the GitLab API group - Name: 'Get Pipelines' - Method: GET - URL: `https://gitlab.com/api/v4/projects/{project_id}/pipelines` - Add a URL parameter `project_id` (Bubble treats this as dynamic) - Add a query parameter `per_page`: `10` (limits to last 10 pipelines) - Set 'Use as': Data - Initialize — provide your actual numeric project ID when prompted. A successful response returns an array of pipeline objects with fields: `id`, `status` (created/pending/running/failed/success/canceled/skipped), `ref` (branch name), `created_at`, `updated_at`. Call 2 — Get Open Issues: - Add another call, name 'Get Issues' - Method: GET - URL: `https://gitlab.com/api/v4/projects/{project_id}/issues` - Parameters: `state=opened`, `per_page=25` - Set 'Use as': Data - Initialize with your project ID Call 3 — Get Merge Requests: - Name: 'Get Merge Requests' - Method: GET - URL: `https://gitlab.com/api/v4/projects/{project_id}/merge_requests` - Parameters: `state=opened`, `per_page=25` - Set 'Use as': Data - Initialize Call 4 — Trigger Pipeline (for the Deploy button): - Name: 'Trigger Pipeline' - Method: POST - URL: `https://gitlab.com/api/v4/projects/{project_id}/pipeline` - JSON body: `{"ref": "main"}` (or whichever branch to trigger) - Set 'Use as': Action - Note: triggering a pipeline via the projects API requires `api` scope on your token (not `read_api`)
1GET https://gitlab.com/api/v4/projects/{project_id}/pipelines2Headers:3 PRIVATE-TOKEN: <private>4 Content-Type: application/json5Query Params:6 per_page: 1078Example response item:9{10 "id": 1234,11 "status": "success",12 "ref": "main",13 "sha": "a1b2c3d4",14 "created_at": "2026-07-09T14:30:00.000Z",15 "updated_at": "2026-07-09T14:45:00.000Z",16 "web_url": "https://gitlab.com/org/repo/-/pipelines/1234"17}Pro tip: After initializing all calls, you can re-initialize any individual call by clicking 'Re-initialize call' on it. This is needed if GitLab's API response shape changes or if you need Bubble to detect a new field that didn't appear in the first sample response.
Expected result: All four calls are initialized. Bubble shows pipeline status fields, issue fields (title, assignee, labels), and merge request fields. The Trigger Pipeline action is ready for workflow use.
Build a Bubble pipeline dashboard with conditional color coding
Design the Bubble page that displays your GitLab DevOps data. The most powerful UI feature for a pipeline dashboard is conditional color coding — pipeline status values map naturally to colors. Go to the Design tab. Create a new page or use an existing one. Add a Repeating Group for pipelines: - Type of content: 'GitLab Get Pipelines' - Data source: 'Get data from external API' → GitLab - Get Pipelines → project_id: your project ID - Layout: Full List with columns for status, branch, and time Inside the first Repeating Group cell: - A Text element for the pipeline ID (bind to current cell's id field) - A Text element for the branch name (bind to ref) - A Text element for the status (bind to status) - A Shape or Group element as a status indicator dot To add color coding on the status indicator Shape: - Click the Shape element → go to the 'Conditional' tab in the properties panel - Add condition 1: 'When: Current cell's GitLab Get Pipelines's status = success' → Change Style: Background color = green (#28a745) - Add condition 2: 'When: status = failed' → Background color = red (#dc3545) - Add condition 3: 'When: status = running' → Background color = blue (#007bff) - Add condition 4: 'When: status = pending OR status = created' → Background color = yellow (#ffc107) - Default (no condition matches): gray (#6c757d) Below the pipeline Repeating Group, add a second Repeating Group for open issues and a third for merge requests, following the same pattern with their respective API calls. For the 'Deploy to Staging' button: - Add a Button element, label it 'Trigger Deployment' - Create a Workflow: on button click → Plugins → GitLab - Trigger Pipeline → project_id: your project ID, ref: 'staging' - Add a second workflow action: Show element → a 'Deployment triggered!' text alert Rate limit awareness: GitLab's API has a rate limit of approximately 10 requests per second per IP (this applies to Bubble's server IP, shared across all your Bubble users). If your dashboard loads 3 API calls on page load and you have 50+ concurrent users, you may approach this limit. Mitigate by caching pipeline and issue data in a Bubble data type and refreshing it every 5 minutes via a scheduled API workflow (paid Bubble plan), rather than calling GitLab on every page load.
Pro tip: GitLab pipeline status values are: created, pending, running, failed, success, canceled, and skipped. Map all of them in your conditional formatting — a missing status case will default to the un-styled text, which can look broken on a dashboard.
Expected result: The Bubble page displays live GitLab pipeline status with color-coded indicators, open issues list, and merge request overview. The 'Trigger Deployment' button fires a pipeline run in GitLab successfully.
Set up inbound GitLab webhooks to Bubble Backend Workflows
GitLab can send webhook events to an external URL when specific events occur — pushes, pipeline completions, issue updates, merge request events. You can use a Bubble Backend Workflow URL as the target, so Bubble automatically reacts to GitLab events (e.g., update a cached pipeline record when GitLab signals a pipeline completed). Prerequisite: Backend Workflows require a paid Bubble plan. The Free plan cannot expose webhook endpoints. If you're on the Free plan, implement a manual 'Refresh Data' button instead. For paid plan users: 1. In Bubble editor → Settings → API → enable 'This app exposes a Workflow API'. Save. 2. Go to Backend Workflows section. Click 'Add API Workflow'. Name it 'gitlab_pipeline_event'. 3. Click 'Detect request data'. Bubble shows the initialization URL: `https://yourappname.bubbleapps.io/api/1.1/wf/gitlab_pipeline_event/initialize` 4. In GitLab, go to your project → Settings → Webhooks → Add new webhook. 5. Paste the PRODUCTION URL (without /initialize): `https://yourappname.bubbleapps.io/api/1.1/wf/gitlab_pipeline_event` 6. In the 'Secret token' field, enter a random string you'll also store in a Bubble workflow condition for verification. 7. Check 'Pipeline events' and 'Issues events'. Click 'Add webhook'. 8. GitLab has a 'Test' button — click it to send a test payload. Bubble receives the payload and you can now map detected fields in the Backend Workflow. 9. Add workflow actions: create or modify a 'GitLabPipeline' data type record with the incoming status, project ID, and pipeline ID from the detected data. RapidDev's team has built real-time DevOps dashboards in Bubble with GitLab webhook integration — if you want expert help setting up the full pipeline notification system, book a free scoping call at rapidevelopers.com/contact.
1Production webhook endpoint URL:2https://yourappname.bubbleapps.io/api/1.1/wf/gitlab_pipeline_event34Example GitLab pipeline webhook payload:5{6 "object_kind": "pipeline",7 "object_attributes": {8 "id": 1234,9 "ref": "main",10 "status": "success",11 "duration": 120,12 "finished_at": "2026-07-09T14:45:00.000Z"13 },14 "project": {15 "id": 567,16 "name": "My App",17 "web_url": "https://gitlab.com/org/my-app"18 }19}Pro tip: The /initialize URL suffix is only for Bubble to detect the incoming webhook payload shape. Never register the /initialize URL in GitLab — use only the production URL (without /initialize suffix) in GitLab's webhook settings.
Expected result: GitLab sends webhook events to your Bubble Backend Workflow. Bubble detects the payload fields (pipeline status, project, ref) and processes the event — updating cached data or creating notifications automatically.
Common use cases
Internal dev dashboard with pipeline health and issue tracking
Display GitLab pipeline status (running, failed, success), open issue count, and latest merge requests in a Bubble internal tool accessible to the entire team — no GitLab accounts or logins required for viewers.
Show the last 5 pipeline runs for my GitLab project with their status (color coded green/red/gray) and duration in a Bubble repeating group
Copy this prompt to try it in Bubble
One-click pipeline trigger from a Bubble button
Give non-technical team members a 'Deploy to Staging' button in a Bubble app that fires a POST call to GitLab's pipeline trigger API. The deployment starts in GitLab, and a Bubble status indicator updates automatically when the pipeline completes.
Add a workflow in Bubble so clicking 'Deploy to Staging' triggers a GitLab CI/CD pipeline for project ID 123 and shows a loading state while it runs
Copy this prompt to try it in Bubble
Real-time issue and merge request review dashboard
Pull open issues assigned to specific team members and pending merge requests awaiting review into a Bubble dashboard with filtering by label, assignee, or milestone — giving product managers visibility into sprint progress without using GitLab's interface.
List all open GitLab issues with label 'bug' in my project, filtered by milestone, in a Bubble table with assignee names and creation dates
Copy this prompt to try it in Bubble
Troubleshooting
API calls return 401 Unauthorized
Cause: The header is named 'Authorization' instead of 'PRIVATE-TOKEN', or the token lacks the required scope, or the token has expired.
Solution: In Bubble's API Connector, verify the shared header name is exactly 'PRIVATE-TOKEN' — not 'Authorization: Bearer' or any other format. Check that the token was created with at least 'read_api' scope (or 'api' scope for write operations). If the token has expired (GitLab now requires expiry dates on tokens), generate a new token in GitLab and update it in Bubble.
API returns 404 Not Found for project-specific endpoints
Cause: The project ID in the URL is wrong, or the token doesn't have access to that GitLab project. GitLab returns 404 (not 403) for projects the token can't access, to avoid leaking project existence information.
Solution: Confirm your project's numeric ID in GitLab → your project page → Settings → General → Project ID (shown at the top). Note: this is the numeric ID (like 12345678), not the project name or path. Also verify the token has 'Reporter' access or higher on the project — tokens from accounts with no project access return 404.
Dashboard works fine with a few users but starts returning 429 Too Many Requests with more traffic
Cause: GitLab's rate limit is per IP address (approximately 10 requests/second). Bubble shares a server IP across all users — if many users simultaneously trigger GitLab API calls (e.g., all load the dashboard at once), the shared IP can exceed the limit.
Solution: Implement a caching strategy: store pipeline and issue data in a Bubble data type with a 'last_updated' timestamp. On page load, check if the cached data is less than 5 minutes old — if yes, display cached data; if no, call the GitLab API and update the cache. This requires a scheduled Backend Workflow on a paid Bubble plan, or can be implemented with a manual 'Refresh' button on the Free plan.
Triggering a pipeline via POST returns 400 Bad Request
Cause: The pipeline trigger POST requires a CI/CD trigger token (from Settings → CI/CD → Pipeline Triggers), not just the Personal Access Token. Alternatively, the request body's 'ref' field points to a branch that doesn't exist.
Solution: For the projects API pipeline trigger (POST /projects/{id}/pipeline), you can use the Personal Access Token with 'api' scope — this is different from the pipeline trigger endpoint (POST /projects/{id}/trigger/pipeline) which uses a separate CI/CD trigger token. Confirm you're using the correct endpoint and that the 'ref' value matches an existing branch name in your repository.
Backend Workflows section is missing and the 'Workflow API' option doesn't appear in Settings
Cause: Backend Workflows are a paid Bubble plan feature. They are not available on the Free plan.
Solution: Upgrade to a paid Bubble plan to access the Workflow API and Backend Workflows feature, which is required for receiving inbound GitLab webhooks. As an alternative on the Free plan, build a manual 'Refresh' button that re-triggers the GitLab API calls to update displayed data.
Best practices
- Use 'PRIVATE-TOKEN' as the exact header name — not 'Authorization' or 'Bearer'. This is GitLab's specific header format and using the wrong name causes 401 errors on all calls.
- Use 'read_api' scope for read-only Bubble dashboards and 'api' scope only when your Bubble app needs to trigger pipelines or create issues — the principle of least privilege reduces risk.
- Cache GitLab API responses in a Bubble data type updated every 5 minutes rather than calling the API on every page load — GitLab's per-IP rate limit can be hit quickly when multiple Bubble users load the dashboard simultaneously.
- Always mark the PRIVATE-TOKEN header as Private in the Bubble API Connector — a non-Private token is visible in every user's browser network tab.
- Set an expiry date on your GitLab Personal Access Token (GitLab now requires this) and create a calendar reminder to rotate the token before it expires, updating Bubble's API Connector at the same time.
- For self-hosted GitLab, update the base URL in the API Connector to match your instance — the API path structure is identical, only the domain differs.
- Map all GitLab pipeline status values (created, pending, running, failed, success, canceled, skipped) to conditional colors in Bubble — missing a status value results in an unstyled fallback.
- Add Privacy Rules in Bubble's Data tab for any data types that cache GitLab pipeline or issue data — prevent unauthenticated users from reading your development data.
Alternatives
Git is a version-control protocol, not a hosted platform with a REST API. If you want to connect Bubble to source code workflows, GitLab's hosted REST API is the right choice. The Git brief covers connecting Bubble to git-based deployment tooling rather than a hosted API.
Jenkins is a self-hosted CI/CD server with its own REST API. If your team uses Jenkins instead of GitLab CI, the Bubble API Connector integration follows a similar pattern but uses Jenkins-specific auth (API token or basic auth). GitLab's advantage is that CI/CD is bundled with source control — one API, one token, full DevOps picture.
Travis CI is a cloud CI/CD service (separate from source control). It has a REST API for build status, but you'd need both a GitHub/GitLab API and a Travis API to get the full DevOps picture in Bubble. GitLab's native CI/CD integration simplifies this to a single API.
Frequently asked questions
What is the difference between GitLab and Git for Bubble integration purposes?
Git is a decentralized version-control protocol — it runs locally on developer machines and has no hosted REST API. GitLab is a hosted platform built on top of Git that adds project management, issue tracking, CI/CD pipelines, and merge requests, all accessible via a REST API. When you 'connect Bubble to GitLab,' you're connecting to the GitLab REST API, not to Git itself. There is no 'Git API' — Git is a protocol, not a service.
Do I need a paid GitLab plan to use the API from Bubble?
No — GitLab's REST API is available on the Free tier, including pipeline data, issues, and merge requests. You can build a fully functional Bubble DevOps dashboard on GitLab Free. A paid GitLab plan is only needed for specific premium features (like Project Access Tokens on Premium, or advanced CI/CD features). Bubble's API Connector can call the GitLab Free tier API without any GitLab subscription upgrade.
Why does Bubble use 'PRIVATE-TOKEN' as the header instead of 'Authorization: Bearer'?
This is GitLab's historical API design. GitLab introduced their custom PRIVATE-TOKEN header format before Bearer tokens became the standard OAuth 2.0 pattern. GitLab also supports 'Authorization: Bearer {oauth_token}' if you use OAuth 2.0 flow, but for Personal Access Tokens the correct header is PRIVATE-TOKEN. Using 'Authorization: Bearer {personal_access_token}' will return 401 — it only works for OAuth tokens, not PATs.
Can I connect Bubble to a self-hosted GitLab instance?
Yes — the GitLab REST API structure is identical whether you use gitlab.com or a self-hosted instance. Simply change the base URL in Bubble's API Connector from 'https://gitlab.com/api/v4' to 'https://your-gitlab-host.com/api/v4'. Everything else — headers, endpoints, response formats — is the same. Ensure your self-hosted GitLab instance is accessible over HTTPS from the public internet (Bubble's servers need to reach it).
Do I need a paid Bubble plan to receive GitLab webhook events?
Yes — receiving inbound webhooks from GitLab requires Bubble's Backend Workflows feature, which is only available on paid Bubble plans. On the Free plan, you can still read GitLab data and trigger pipelines (outbound calls), but you cannot expose a webhook endpoint for GitLab to call. As a workaround on the Free plan, use a 'Refresh' button that the user clicks to re-fetch latest GitLab data.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation