Skip to main content
RapidDev - Software Development Agency
bubble-integrationsBubble API Connector

Jenkins

Connect Bubble to Jenkins through the Bubble API Connector with Basic Auth (username + API token, not password). Reading job status is straightforward REST — but triggering a build requires two chained Backend Workflow steps: first GET /crumbIssuer/api/json for a CSRF crumb, then POST to /job/{name}/build with that crumb as a header. Jenkins must be publicly accessible (not behind a private VPN) before any Bubble work can begin, and both the crumb chain and scheduled polling require a Bubble paid plan.

What you'll learn

  • Why Jenkins must be publicly internet-accessible before any Bubble integration can work, and how to expose a private-network Jenkins server
  • How to generate a Jenkins API token (separate from your Jenkins password) and configure Basic Auth in Bubble's API Connector
  • Why the 'tree' parameter is essential for every Jenkins /api/json call to prevent response-size overflows in Bubble
  • How to fetch a Jenkins-Crumb from /crumbIssuer/api/json and chain it with a build trigger POST in a Bubble Backend Workflow
  • How parameterized builds work (POST to /buildWithParameters with form-urlencoded body, not JSON)
  • How to handle Jenkins' HTTP 201 response to successful build triggers (instead of the typical 200)
  • How to set up a Scheduled Backend Workflow for periodic Jenkins job status refresh in Bubble's database
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Advanced22 min read3–5 hours (after resolving Jenkins network accessibility)DevOps & ToolsLast updated July 2026RapidDev Engineering Team
TL;DR

Connect Bubble to Jenkins through the Bubble API Connector with Basic Auth (username + API token, not password). Reading job status is straightforward REST — but triggering a build requires two chained Backend Workflow steps: first GET /crumbIssuer/api/json for a CSRF crumb, then POST to /job/{name}/build with that crumb as a header. Jenkins must be publicly accessible (not behind a private VPN) before any Bubble work can begin, and both the crumb chain and scheduled polling require a Bubble paid plan.

Quick facts about this guide
FactValue
ToolJenkins
CategoryDevOps & Tools
MethodBubble API Connector
DifficultyAdvanced
Time required3–5 hours (after resolving Jenkins network accessibility)
Last updatedJuly 2026

Bubble + Jenkins: a deployment trigger and CI status portal for non-technical teams

Jenkins occupies a unique position in the DevOps landscape: it is the most flexible and widely deployed CI/CD platform, and also the most complex to integrate from Bubble. Unlike Travis CI (hosted SaaS with a clean API) or GitHub Actions (cloud-native, REST-accessible), Jenkins is self-hosted software that lives on servers you manage — servers that are usually on a private corporate network, behind a firewall, not accessible from the public internet.

This means the first challenge of a Bubble + Jenkins integration is not Bubble at all — it is network architecture. Bubble's servers need to reach your Jenkins server over HTTPS. If Jenkins is on a private network (a typical AWS VPC, a corporate data center, or even a Raspberry Pi at an office), Bubble Cloud cannot connect to it until you expose the Jenkins API port publicly. This requires IT involvement and a deliberate architecture decision, not a Bubble configuration change.

Once Jenkins is accessible, the second challenge is CSRF protection. Jenkins includes cross-site request forgery protection on all write operations (build triggers, configuration changes). Every POST request to Jenkins must include a Jenkins-Crumb header — a session-bound token fetched from /crumbIssuer/api/json moments before the POST. In a browser or Postman session, this is handled automatically; in Bubble's API Connector, you must chain two operations explicitly in a Backend Workflow.

The third consideration is response size. Jenkins' /api/json responses for job lists can be extremely large — containing nested build history, artifact lists, parameter definitions, and test results for every job. Without the 'tree' parameter to limit fields, these responses can exceed what Bubble's API Connector can parse reliably. The 'tree' parameter is a Jenkins-specific filter that says 'return only these specific fields' and is essential in every Bubble API call to Jenkins.

Once these three concerns are addressed, the Bubble integration unlocks a genuinely useful product: a clean interface where a non-technical product manager selects an environment (staging, production) from a Bubble dropdown and clicks 'Deploy' — triggering the right Jenkins job without needing Jenkins access, pipeline knowledge, or CLI commands.

Integration method

Bubble API Connector

The Bubble API Connector uses Basic Auth (Authorization: Basic base64(username:api_token)) for all Jenkins calls. Read operations (job status, build history) work directly; write operations (build triggers) require a two-step Backend Workflow: fetch a Jenkins-Crumb from /crumbIssuer/api/json, then POST to the build endpoint with the crumb as a header.

Prerequisites

  • A Jenkins server with the REST API port (typically 8080 or the configured HTTPS port) publicly accessible — Jenkins on a private network cannot be reached by Bubble Cloud until exposed via a reverse proxy or tunnel
  • A valid public CA-signed SSL certificate on the Jenkins server or reverse proxy — Bubble's API Connector rejects self-signed certificates
  • A Jenkins user account with 'Read' permission to the jobs you want to display, and 'Build' permission if you are implementing build triggers — use the principle of least privilege
  • A Jenkins API token (not your login password) — generated at Jenkins → your profile icon → 'Configure' → 'API Token' → 'Add new Token'
  • A Bubble app on Starter plan or above for build triggering (crumb + POST chain requires Backend Workflows) and scheduled polling; free plan supports read-only job list display on page load
  • The free API Connector plugin by Bubble installed in your app (Plugins → Add plugins → search 'API Connector')
  • Your Jenkins base URL (e.g., https://jenkins.company.com) confirmed reachable from a browser outside your corporate network

Step-by-step guide

1

Step 1 — Expose Jenkins publicly and generate an API token

Before any Bubble configuration, confirm that your Jenkins server is reachable from the public internet. Open a browser not connected to your corporate VPN or office network and navigate to https://jenkins.company.com/api/json?tree=jobs[name,color] (replace with your Jenkins URL). If you see a JSON response, Jenkins is accessible. If you see a connection timeout, Jenkins is not publicly reachable and you need to resolve this first. Common solutions: (1) configure nginx or Apache as a reverse proxy on a publicly accessible server that forwards to the internal Jenkins instance, (2) use Cloudflare Tunnel (cloudflared daemon running on the Jenkins server) to create a public HTTPS URL without opening firewall ports — this is often the fastest path with minimal IT friction, (3) if Jenkins runs on a cloud VM (AWS EC2, DigitalOcean Droplet), confirm the security group or firewall allows inbound HTTPS traffic on the Jenkins port. Once publicly accessible, generate a Jenkins API token: log into Jenkins → click your username in the top-right → 'Configure' → scroll to 'API Token' → click 'Add new Token' → name it 'Bubble Integration' → click 'Generate' → copy the token immediately (it is shown only once). Keep your Jenkins base URL and API token ready for the next step.

jenkins-accessibility-reference.txt
1// Jenkins API accessibility check
2// From a browser NOT on corporate VPN:
3// https://jenkins.company.com/api/json?tree=jobs[name,color]
4
5// Expected response if accessible and authenticated:
6// { "jobs": [{"name": "my-app", "color": "blue"}, ...] }
7
8// API token location:
9// Jenkins → your username (top-right) → Configure
10// → API Token section → Add new Token → Generate → COPY IMMEDIATELY
11
12// Basic Auth format for Jenkins:
13// Authorization: Basic base64("username:api_token")
14// Example with username 'jenkins_user' and token 'abc123':
15// base64("jenkins_user:abc123") = 'amVua2luc191c2VyOmFiYzEyMw=='
16// Full header: Authorization: Basic amVua2luc191c2VyOmFiYzEyMw==
17
18// Network exposure options for private-network Jenkins:
19// Option A: Cloudflare Tunnel (no inbound firewall rules needed)
20// Option B: nginx reverse proxy on a public server
21// Option C: If on AWS: configure Elastic Load Balancer → public
22// Option D: Bubble Dedicated Cluster + VPN peering (advanced/enterprise)

Pro tip: Cloudflare Tunnel is the fastest way to expose a private Jenkins server without IT approval for firewall changes. Install the cloudflared agent on the Jenkins host (or any host with network access to Jenkins), authenticate with a Cloudflare account, and get a public HTTPS URL with a valid Cloudflare-issued certificate in under 10 minutes. The Bubble API Connector will trust Cloudflare's certificate immediately.

Expected result: Jenkins responds to an API JSON request from a public network browser. You have a Jenkins API token copied and saved. You know the public HTTPS URL for your Jenkins instance.

2

Step 2 — Configure the Bubble API Connector with Jenkins Basic Auth

Open your Bubble app editor → Plugins → API Connector. If the API Connector plugin is not installed, click 'Add plugins,' search for 'API Connector,' and install it (free). Return to Plugins → API Connector → click 'Add another API.' Name this group 'Jenkins.' In the 'Root URL' field, enter your Jenkins base URL: for example https://jenkins.company.com (no trailing slash, no /api/json path). Under 'Authentication,' select 'Basic auth' from the dropdown instead of leaving it as 'None.' Enter your Jenkins username in the 'Username' field and your Jenkins API token in the 'Password' field (the API token goes in the Password slot, even though it is not your login password). Bubble will base64-encode these automatically and send them as an Authorization: Basic header on every call. Check the 'Private' option next to the credentials — this ensures they are server-side only. Do not set a shared Authorization header manually when using Basic auth mode — Bubble handles the encoding and header injection automatically. Add one shared header at the group level: key 'Accept,' value 'application/json' (Jenkins returns JSON when this header is present).

api-connector-jenkins-group.json
1// Bubble API Connector — Jenkins group configuration
2{
3 "api_group_name": "Jenkins",
4 "root_url": "https://jenkins.company.com",
5 "authentication": "Basic auth",
6 "username": "your_jenkins_username",
7 "password": "your_jenkins_api_token",
8 "credentials_private": true,
9 "shared_headers": [
10 {
11 "key": "Accept",
12 "value": "application/json"
13 }
14 ]
15}
16
17// The 'password' field is the Jenkins API TOKEN, not the login password.
18// Bubble handles the Base64 encoding automatically when 'Basic auth' is selected.
19// Result header sent on every call:
20// Authorization: Basic base64("username:api_token")
21
22// Never put the Jenkins API token in a shared 'Authorization' header manually
23// when Bubble's Basic auth mode is already enabled — duplicate auth headers
24// can cause unexpected behavior.

Pro tip: Jenkins API tokens are tied to a specific Jenkins user account. If that user is deactivated or changes their token, the Bubble integration will start returning 403 errors. For production integrations, create a dedicated Jenkins service account ('bubble-service') with the minimum required permissions (Overall/Read + Job/Read + Job/Build) and use that account's API token — this decouples the integration from individual user accounts.

Expected result: The Jenkins API Connector group exists with root URL, Basic auth credentials (marked Private), and an Accept: application/json shared header. No individual calls have been added yet.

3

Step 3 — Add the 'List Jobs' call with the tree parameter

Inside the Jenkins API Connector group, click 'Add call.' Name this call 'List Jobs.' Set method to GET. The endpoint is /api/json — Jenkins' root API endpoint that returns all jobs. This is where the 'tree' parameter is critical: without it, Jenkins returns every job's full nested detail including all build history, test reports, artifacts, and configuration — potentially megabytes of JSON that Bubble may fail to parse or may parse very slowly. In the URL parameters section, add a parameter named 'tree' with the value: jobs[name,color,url,lastBuild[number,result,duration,timestamp,url,displayName,building]]. This tells Jenkins to return only the fields you actually need: the job name, its color-coded status (blue=passing, red=failing, grey=no builds), and the last build's key fields. Set 'Use as' to 'Data.' Click 'Initialize call.' Bubble fires a GET request with your Basic auth credentials and the tree parameter. Jenkins returns a JSON object with a 'jobs' array. Bubble detects the fields in each job object: name, color, url, and the nested lastBuild fields. Click 'Save.' The 'color' field is Jenkins' build status indicator: 'blue' means last build passed, 'red' means failed, 'grey' or 'notbuilt' means no builds yet, and '_anime' suffix (e.g., 'blue_anime') means a build is currently running.

jenkins-list-jobs-call.json
1// Bubble API Connector — Jenkins 'List Jobs' call
2{
3 "call_name": "List Jobs",
4 "method": "GET",
5 "endpoint": "/api/json",
6 "parameters": [
7 {
8 "key": "tree",
9 "value": "jobs[name,color,url,lastBuild[number,result,duration,timestamp,url,displayName,building]]"
10 }
11 ],
12 "use_as": "Data"
13}
14
15// Jenkins response:
16// {
17// "jobs": [
18// {
19// "name": "deploy-staging",
20// "color": "blue",
21// "url": "https://jenkins.company.com/job/deploy-staging/",
22// "lastBuild": {
23// "number": 42,
24// "result": "SUCCESS",
25// "duration": 183000,
26// "timestamp": 1751990520000,
27// "displayName": "#42",
28// "building": false
29// }
30// }
31// ]
32// }
33
34// Jenkins 'color' field values:
35// 'blue' = last build PASSED
36// 'red' = last build FAILED
37// 'yellow' = last build UNSTABLE
38// 'grey' = no builds yet
39// 'disabled' = job disabled
40// 'blue_anime' = currently building (was passing)
41// 'red_anime' = currently building (was failing)

Pro tip: The 'tree' parameter syntax supports nested brackets for nested objects and comma-separated field names. Start with a minimal tree (just name and color) during development to confirm the auth and connectivity work, then expand the tree to include lastBuild fields once the basic call is working. Debugging a Bubble API Connector issue with a 500KB response is much harder than debugging with a 2KB response.

Expected result: The 'List Jobs' call is initialized. Bubble detects the 'jobs' list with each item containing name, color, url, and nested lastBuild fields. The tree parameter limits the response to only the requested fields. The call is set to 'Use as: Data.'

4

Step 4 — Add the crumb fetch call and the build trigger POST

Build triggering in Jenkins requires two API calls chained in a specific order. Add the first call: click 'Add call,' name it 'Get Jenkins Crumb.' Method: GET. Endpoint: /crumbIssuer/api/json. Set 'Use as' to 'Data.' No additional parameters needed. Click 'Initialize call.' Jenkins returns: {'crumb': 'CRUMB_VALUE', 'crumbRequestField': 'Jenkins-Crumb'}. The 'crumb' field is the value you need. The 'crumbRequestField' tells you the header name to use (always 'Jenkins-Crumb' in modern Jenkins). Click 'Save.' Now add the build trigger call: click 'Add call,' name it 'Trigger Build.' Method: POST. Endpoint: /job/{job_name}/build (where {job_name} is a dynamic parameter). Add a call-level header: key = 'Jenkins-Crumb,' value = a dynamic parameter named 'crumb_value' (you will pass the fetched crumb into this from the Backend Workflow). Leave the body empty — a simple build trigger needs no body (parameterized builds use a different endpoint covered in the tip below). Set 'Use as' to 'Action.' Important: Jenkins returns HTTP 201 (Created) for a successful build queue entry — not the usual 200. Bubble treats 201 as success, but verify this in the Logs tab if the workflow seems to fail despite the build being queued. Click 'Save.'

jenkins-crumb-and-trigger-calls.json
1// Call 1: Get Jenkins Crumb
2{
3 "call_name": "Get Jenkins Crumb",
4 "method": "GET",
5 "endpoint": "/crumbIssuer/api/json",
6 "use_as": "Data"
7}
8
9// Crumb response:
10// {
11// "_class": "hudson.security.csrf.DefaultCrumbIssuer",
12// "crumb": "a1b2c3d4e5f6g7h8i9j0...",
13// "crumbRequestField": "Jenkins-Crumb"
14// }
15
16// Call 2: Trigger Build (non-parameterized)
17{
18 "call_name": "Trigger Build",
19 "method": "POST",
20 "endpoint": "/job/{job_name}/build",
21 "call_level_headers": [
22 {
23 "key": "Jenkins-Crumb",
24 "value": "<dynamic: crumb_value parameter>"
25 }
26 ],
27 "body": "",
28 "use_as": "Action"
29}
30
31// Note: Jenkins returns HTTP 201 Created for successful build queue entry
32// The build is queued, not immediately started
33// To check queue status: GET /queue/api/json
34
35// For PARAMETERIZED builds, use this endpoint instead:
36// POST /job/{job_name}/buildWithParameters
37// Body type: Form data (NOT JSON)
38// Form fields: ENVIRONMENT=staging&BRANCH=main

Pro tip: For parameterized Jenkins builds (where the job accepts input parameters like ENVIRONMENT or BRANCH), use the endpoint /job/{job_name}/buildWithParameters instead of /job/{job_name}/build. Critically: the body type for buildWithParameters must be set to 'Form Data' in Bubble's API Connector, not 'JSON.' Jenkins expects form-urlencoded key-value pairs for parameterized build inputs, and sending them as JSON will result in the parameters being ignored and the build running with default values.

Expected result: The 'Get Jenkins Crumb' call is initialized and returns a crumb value. The 'Trigger Build' POST call is configured with a dynamic Jenkins-Crumb header. Both calls are saved in the Jenkins API Connector group.

5

Step 5 — Wire the crumb + trigger chain as a two-step Backend Workflow

The crumb and build trigger must run as a sequential Backend Workflow because the crumb from step one must be passed to step two. Navigate to Backend Workflows in the Bubble editor (Starter plan required). Click 'Add a new API Workflow' and name it 'Jenkins Trigger Build.' Add an input parameter to this workflow: parameter name 'job_name,' type 'text.' This lets calling workflows pass in which Jenkins job to trigger. Inside the workflow, add Step 1: click 'Plugins actions' → choose 'Jenkins > Get Jenkins Crumb' → run this API call. Step 2: click 'Plugins actions' → choose 'Jenkins > Trigger Build.' For the {job_name} parameter, use 'Parameter job_name' (the input parameter). For the crumb_value header parameter, use 'Result of step 1's crumb' — this passes the crumb from step one directly into the header of step two. Save the workflow. Now, from any page workflow in Bubble, you can trigger a Jenkins build by calling 'Schedule API Workflow' → 'Jenkins Trigger Build' with job_name = the name of the Jenkins job. Add a 'Deploy' button on a Bubble page: On click → Schedule API Workflow → 'Jenkins Trigger Build' → job_name = 'deploy-staging' (or a dynamic value from a Dropdown). This gives non-technical users a one-click deploy button without any Jenkins access.

jenkins-trigger-backend-workflow.txt
1// Backend Workflow: 'Jenkins Trigger Build'
2// Navigate to: Backend Workflows section (Starter plan required)
3// This workflow is NOT an API endpoint — it is an internal Bubble workflow
4
5// Input parameter:
6// Name: job_name | Type: text
7
8// Step 1: Call API connector
9// Call: Jenkins > Get Jenkins Crumb
10// (No parameters needed)
11// → Returns: crumb value (string), crumbRequestField (string)
12
13// Step 2: Call API connector
14// Call: Jenkins > Trigger Build
15// job_name = Parameter job_name
16// crumb_value = Result of step 1's crumb
17
18// To call this workflow from a page:
19// Button click → Schedule API Workflow
20// Workflow: Jenkins Trigger Build
21// Scheduled time: Current date/time
22// job_name = "deploy-staging" (or Dropdown's value)
23
24// For parameterized builds (separate workflow):
25// Name: Jenkins Trigger Parameterized Build
26// Parameters: job_name (text), environment (text), branch (text)
27// Step 1: Get Jenkins Crumb
28// Step 2: Call 'Trigger Parameterized Build'
29// job_name = Parameter job_name
30// crumb_value = Step 1's crumb
31// ENVIRONMENT = Parameter environment
32// BRANCH = Parameter branch

Pro tip: Jenkins crumbs are session-bound and should be used immediately after fetching — they expire when the Jenkins session ends. Because the crumb fetch (Step 1) and the build trigger (Step 2) run in the same Backend Workflow execution, the crumb is always fresh and valid when Step 2 uses it. Do not try to cache or reuse crumbs across multiple workflow runs.

Expected result: The 'Jenkins Trigger Build' Backend Workflow exists with a job_name parameter. Step 1 fetches the Jenkins crumb; Step 2 uses it to POST to the build endpoint. A 'Deploy' button on a Bubble page can call this workflow and queue a Jenkins build without the user needing Jenkins access.

6

Step 6 — Build the Jenkins job status dashboard with scheduled data refresh

Create a Bubble page named 'ci-dashboard' or 'devops-portal.' First, create a Bubble data type 'JenkinsJob' with fields: job_name (text), job_url (text), last_build_status (text), last_build_number (number), last_build_duration (number), last_build_at (date), is_building (yes/no). Set up a Scheduled Backend Workflow (name it 'Sync Jenkins Status') that runs the 'List Jobs' API call, then for each job in the result creates or updates a JenkinsJob record using job_name as the deduplication key. Schedule this workflow to recur every 300 seconds (5 minutes). On the dashboard page: add a Repeating Group with type JenkinsJob, data source = search for JenkinsJob sorted by last_build_at descending. In each cell: display job_name, a colored status badge conditional on last_build_status ('SUCCESS'=green, 'FAILURE'=red, 'UNSTABLE'=yellow, 'ABORTED'=gray, building=blue pulsing). Add a 'Last synced:' text at the top. For the deploy trigger: add a Dropdown listing JenkinsJob names, an optional Environment text input, and a 'Deploy' button that calls the 'Jenkins Trigger Build' Backend Workflow with the selected job name. Add a workflow on successful trigger to show an alert: 'Build queued! Check Jenkins for status in a few minutes.' If you need help architecting a Bubble + Jenkins internal DevOps portal, RapidDev's team has built these — book a free scoping call at rapidevelopers.com/contact.

jenkins-dashboard-setup.txt
1// Bubble data type: JenkinsJob
2// Data → Data types → JenkinsJob
3// Fields:
4// job_name — text (deduplication key)
5// job_url — text
6// last_build_status — text (SUCCESS | FAILURE | UNSTABLE | ABORTED | IN_PROGRESS)
7// last_build_number — number
8// last_build_duration — number (milliseconds)
9// last_build_at — date
10// is_building — yes/no
11
12// Backend Workflow: 'Sync Jenkins Status'
13// Step 1: Call Jenkins > List Jobs
14// Step 2: Schedule API Workflow on a list
15// List: Result of step 1's jobs
16// Sub-workflow: Upsert JenkinsJob
17// Search for JenkinsJob where job_name = current item's name
18// If found: update all fields
19// If not found: Create new JenkinsJob
20
21// Schedule: Every 300 seconds (5 minutes)
22
23// Dashboard status badge conditionals:
24// When last_build_status = "SUCCESS" → background #22c55e (green)
25// When last_build_status = "FAILURE" → background #ef4444 (red)
26// When last_build_status = "UNSTABLE" → background #eab308 (yellow)
27// When last_build_status = "ABORTED" → background #6b7280 (gray)
28// When is_building = yes → background #3b82f6 (blue) + animation
29
30// Deploy button workflow:
31// On click → Schedule API Workflow:
32// Workflow: Jenkins Trigger Build
33// Scheduled time: Current date/time
34// job_name: Dropdown's value (JenkinsJob's job_name)

Pro tip: Add an 'is_building' visual indicator (a pulsing animation or spinner in Bubble's conditionals) for JenkinsJob records where the color field ends in '_anime' (Jenkins' suffix for in-progress builds). This gives users an immediate indication that a build is currently running, preventing double-click deploys while a build is in progress.

Expected result: The Jenkins dashboard displays all jobs with color-coded build status badges and last build timestamps. The Scheduled Backend Workflow keeps data fresh every 5 minutes. The Deploy button triggers a Jenkins build via the two-step crumb + POST Backend Workflow without exposing Jenkins credentials to the user.

Common use cases

Non-technical deployment trigger interface

A Bubble app gives product managers and QA engineers a one-click deploy interface. A dropdown lets users select an environment (staging, production, hotfix) and a branch. Clicking 'Deploy' triggers a Backend Workflow that fetches a Jenkins-Crumb and POSTs to the correct Jenkins parameterized build job. The deploying user does not need Jenkins access.

Bubble Prompt

When Deploy button is clicked: Step 1 — Call Jenkins API 'Get Crumb' and store crumb value. Step 2 — Call Jenkins API 'Trigger Parameterized Build' with job_name = selected job, ENVIRONMENT = dropdown value, BRANCH = text input value, Jenkins-Crumb header = Step 1's crumb field value

Copy this prompt to try it in Bubble

Jenkins job health dashboard for engineering managers

A Bubble dashboard shows all Jenkins jobs with color-coded build status (green/red/gray), last build number, last build branch, and time since last build. Data is synced every 5 minutes via a Scheduled Backend Workflow. Engineering managers check build health at a glance without Jenkins access.

Bubble Prompt

Every 5 minutes, call Jenkins API 'List Jobs' with tree parameter, upsert Bubble JenkinsJob records with job name, color (build status), lastBuild.number, lastBuild.result, lastBuild.timestamp; display in Repeating Group sorted by last build timestamp descending

Copy this prompt to try it in Bubble

Build history log viewer for QA teams

A Bubble detail page for a Jenkins job shows the last 20 builds with build number, result, commit message (if available), duration, and a link to the Jenkins build URL. QA engineers can track which commit introduced a test failure without needing Jenkins access.

Bubble Prompt

On build history page load (job name from URL parameter), call Jenkins API 'Get Job Builds' with job name and tree parameter limiting to builds[number,result,duration,timestamp,displayName]; display in Repeating Group with result badge, duration formatted as minutes, timestamp as relative time

Copy this prompt to try it in Bubble

Troubleshooting

'There was an issue setting up your call' on every Jenkins API call, even the List Jobs call

Cause: Jenkins is not publicly accessible from Bubble's servers. The most common cause is Jenkins running on a private corporate network, a local machine, or a cloud VM with a firewall that blocks inbound HTTPS traffic. A self-signed SSL certificate can also cause connection rejection before the request even reaches Jenkins.

Solution: Test Jenkins accessibility from a browser not on your corporate VPN. Navigate to https://jenkins.company.com/api/json. If it times out or shows a certificate warning, resolve the network exposure issue first (Cloudflare Tunnel, nginx reverse proxy, or firewall rule update). Bubble's API Connector cannot help until Jenkins is reachable with a trusted SSL certificate from the public internet.

API calls return 403 Forbidden even though credentials are correct

Cause: The Jenkins API token was not generated correctly, or the credentials are being submitted as 'Bearer' auth instead of 'Basic' auth. Additionally, Jenkins CSRF protection may be blocking the request if the call is a POST without a crumb header.

Solution: Verify that Bubble's API Connector group is set to 'Basic auth' mode and that the 'password' field contains the Jenkins API token (not the login password). Test the same credentials with Postman using Basic Auth. For POST requests (build triggers), also confirm that the crumb fetching step is running before the POST — a POST to /job/{name}/build without a crumb header returns 403 even with valid credentials.

Build trigger Backend Workflow seems to succeed in Bubble but no build appears in Jenkins

Cause: Jenkins returns HTTP 201 (not 200) for a successfully queued build. If Bubble's API Connector is configured to expect 200 as the success response, it may be treating 201 as a failure and not completing the workflow — yet Jenkins still queued the build. Alternatively, the Jenkins-Crumb header value may be empty if step one's crumb detection failed.

Solution: Check Jenkins → Build Queue in the Jenkins UI to see if builds are being queued but not showing in the job history. If they are in the queue, the trigger is working and the issue is Bubble's 201 response handling. In Bubble's Logs tab → Workflow logs, inspect the step 2 response code to confirm. Also check that step 1 of the Backend Workflow correctly returns a non-empty crumb value by examining the log's step 1 response body.

Jenkins List Jobs response causes Bubble to show 'Result too large to parse' or return no fields

Cause: The 'tree' parameter is missing or incorrectly formatted, causing Jenkins to return its full API response which includes complete build history, test results, and artifact metadata for every job — often hundreds of kilobytes of JSON that exceeds Bubble's response parsing capacity.

Solution: Verify the 'tree' parameter is set to: jobs[name,color,url,lastBuild[number,result,duration,timestamp,url]] — with correctly nested brackets and no spaces. Re-initialize the call with this tree parameter. If Bubble still fails to parse the response, further limit the tree: jobs[name,color] is the minimum viable set for a status dashboard.

Parameterized build is triggered but ignores all parameters (runs with default values)

Cause: The parameterized build endpoint (/buildWithParameters) requires a Form Data body, not a JSON body. Bubble's API Connector defaults to JSON for POST bodies. If the body type is set to JSON and you send {"ENVIRONMENT": "staging"}, Jenkins ignores the parameters.

Solution: For the 'Trigger Parameterized Build' call, set the Body Type to 'Form Data' in Bubble's API Connector. Then add the parameters as form fields (key-value pairs). The form data encoding (ENVIRONMENT=staging&BRANCH=main) matches what Jenkins expects for parameterized builds.

Best practices

  • Always use the 'tree' parameter on every Jenkins /api/json GET request — Jenkins' default full responses can contain megabytes of nested JSON that exceeds Bubble's API Connector parsing capacity and creates unpredictable initialization failures.
  • Generate a dedicated Jenkins API token for the Bubble integration (named 'bubble-integration') rather than using a personal user API token — this prevents the integration from breaking when a team member changes their password or has their account disabled.
  • Never attempt to cache or reuse Jenkins crumbs across multiple workflow runs — crumbs are session-bound and should be freshly fetched immediately before each build trigger POST in the same Backend Workflow execution.
  • Use a Jenkins service account with the minimum required permissions ('Overall/Read,' 'Job/Read,' and 'Job/Build') for the API token — a full admin token creates unnecessary risk if the token is ever exposed.
  • Implement the dashboard from cached Bubble database records (synced by a Scheduled Backend Workflow) rather than live Jenkins API calls on page load — Jenkins queries can be slow for large job counts, and per-user live calls generate unnecessary WU consumption.
  • Verify Jenkins' response code for build triggers is 201 (not 200) by checking Bubble's Workflow logs after the first successful trigger — treating 201 as an error is a common source of confusion in the two-step crumb + POST workflow.
  • Add a 'Deploy in progress' disabled state to the Deploy button using Bubble's conditional formatting, checking whether the most recent JenkinsJob record for the selected job has is_building = yes — this prevents double-trigger submissions during active builds.
  • Document the Cloudflare Tunnel or reverse proxy configuration that exposes Jenkins publicly as part of your Bubble app's admin notes — if this proxy configuration changes, the Bubble integration silently breaks and the root cause is the proxy, not Bubble.

Alternatives

Frequently asked questions

Does Jenkins integration with Bubble require a paid Bubble plan?

Read-only operations (displaying job status on page load from a live Jenkins API call) work on the Bubble free plan. Build triggering requires Backend Workflows (the two-step crumb + POST chain) which are paid-plan only. Scheduled Backend Workflows for periodic status refresh (keeping a Bubble database in sync with Jenkins) also require a paid plan. For a minimal dashboard that fetches job status on every page load without caching, the free plan is technically sufficient — but it creates per-user live API calls and has no way to trigger builds.

Why does Jenkins need a CSRF crumb for build triggers? Travis CI doesn't require this.

Jenkins was originally designed as a web application and uses CSRF protection to prevent malicious websites from triggering builds by tricking a logged-in Jenkins user's browser. The crumb system is Jenkins' implementation of CSRF tokens — a fresh token required on every state-changing operation. Travis CI is a modern SaaS that authenticates API calls via an API token and doesn't have the same CSRF surface area. Self-hosted Jenkins inherited this protection from its web-app roots.

Can Jenkins send build result webhooks to Bubble instead of Bubble polling?

Yes. Jenkins supports outbound webhooks through plugins like the 'Notification' plugin or via the built-in post-build 'HTTP Request' step. Configure Jenkins to POST to a Bubble Backend Workflow URL after each build. In Bubble, create a Backend Workflow with 'Detect request data' and map the build result fields. The Bubble Backend Workflow URL is https://your-app.bubbleapps.io/api/1.1/wf/your-workflow-name. This eliminates polling and provides near-real-time updates. Note: Bubble Backend Workflow endpoints require Starter plan or above.

The Jenkins API returns 'HTTP 201' for build triggers. Is this correct?

Yes. Jenkins responds with HTTP 201 Created when a build is successfully added to the build queue. The build does not start immediately — it enters the queue and starts when an executor is available. HTTP 201 is the correct success response for the build trigger POST endpoint. Bubble's API Connector should treat 201 as success. Check Bubble's Logs tab → Workflow logs if a trigger appears to fail — the response code helps distinguish between a 201 (success, queued) and a 403 (CSRF error) or 404 (job not found).

How do I trigger a Jenkins job that requires parameters (like ENVIRONMENT=staging)?

Use the /job/{job_name}/buildWithParameters endpoint instead of /job/{job_name}/build. Set the Bubble API Connector body type to 'Form Data' (not JSON) and add the parameters as form key-value pairs. Include the Jenkins-Crumb header from the same two-step crumb fetch workflow. The form data body should contain key=value pairs matching the parameter names defined in the Jenkins job configuration.

Can I run the Jenkins crumb fetch and build trigger as two separate Bubble workflows?

No — you must run them sequentially in the same Backend Workflow. Jenkins crumbs are session-bound and tied to the HTTP session that fetched them. Fetching a crumb in one workflow and passing it to a separate unrelated workflow call may fail if Jenkins creates a new session context between requests. The correct pattern is: Step 1 (Get Crumb) and Step 2 (Trigger Build) inside the same Backend Workflow execution, using 'Result of step 1's crumb' as the crumb_value for step 2.

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 Bubble 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.