# How to Integrate Retool with Jenkins

- Tool: Retool
- Difficulty: Intermediate
- Time required: 30 minutes
- Last updated: April 2026

## TL;DR

Connect Retool to Jenkins using a REST API Resource with Basic Auth (username + API token) and your Jenkins base URL. Jenkins requires CSRF protection — every write operation needs a Jenkins-Crumb header fetched from /crumbIssuer/api/json before the request. Build a Jenkins operations dashboard that views build status across jobs, triggers parameterized builds, reads console output, and manages build queues without leaving your internal tools platform.

## Build a Jenkins Build Operations Dashboard in Retool

Jenkins is the backbone of CI/CD workflows in many engineering organizations, but its native UI is functional rather than elegant — build status monitoring, cross-job comparisons, and build triggering all require multiple navigation steps in Jenkins' web interface. Building a Retool operations dashboard on top of Jenkins' API gives engineering teams, release managers, and DevOps engineers a cleaner, more customizable view of build operations tailored to their workflows.

With a Retool-Jenkins integration, you can build a build status monitor that shows current build health across all jobs with one-click rebuild buttons for failed builds. You can create a deployment control panel that lists deployment jobs with environment-specific parameter forms, allowing teams to trigger production deployments with structured approval workflows. Or you can build a build analytics dashboard that combines Jenkins build duration and success rate data with deployment frequency metrics to track CI/CD pipeline health over time.

The primary technical consideration for Jenkins API integration is CSRF protection. Jenkins enables crumb-based CSRF protection by default, requiring all POST requests to include a fresh Jenkins-Crumb header value obtained from the crumb issuer endpoint. Retool's query chaining system — where one query's on-success handler triggers another query with the first query's result as input — handles this pattern elegantly. Understanding this two-step pattern is the key to building reliable Jenkins write operations in Retool.

## Before you start

- A running Jenkins instance accessible from the internet or your network (self-hosted Jenkins URL, e.g., https://jenkins.yourcompany.com)
- A Jenkins user account with the 'Read' permission for viewing jobs and 'Build' permission if you need to trigger builds
- A Jenkins API token generated from your user profile (different from your Jenkins password)
- A Retool account with permission to create Resources
- Basic understanding of Jenkins concepts: jobs, builds, pipelines, and the Jenkins web UI

## Step-by-step guide

### 1. Generate a Jenkins API token and understand CSRF protection

Jenkins uses API tokens rather than passwords for API authentication — this is both more secure and specifically required for Basic Auth API access. To generate an API token, log in to your Jenkins instance and click on your username in the top-right corner of the Jenkins UI, or navigate directly to https://your-jenkins-url/user/YOUR_USERNAME/configure. On the user configuration page, scroll down to the 'API Token' section. Click 'Add new Token', give it a name like 'Retool Integration', and click 'Generate'. Jenkins displays the token value once — copy it immediately and store it securely. This token is used as the password in Basic Auth: username = your Jenkins username, password = the API token. Next, understand Jenkins CSRF protection: by default, Jenkins requires a CSRF crumb (a security token) for all POST requests. The crumb is obtained from the /crumbIssuer/api/json endpoint and must be included as a request header named 'Jenkins-Crumb' (or sometimes '.crumb' for older Jenkins versions). Crumbs are session-specific and have a limited validity period. In Retool, the pattern for write operations (triggering builds, updating configurations) is: Query 1 fetches the crumb → Query 2's On Success handler triggers the actual build POST using the crumb value from Query 1's result. Some Jenkins configurations disable CSRF protection — if your Jenkins admin has done this, the crumb step is unnecessary. Check with your Jenkins administrator before skipping it.

**Expected result:** You have a Jenkins API token copied and understand the crumb-based CSRF workflow required for POST requests.

### 2. Create the Jenkins REST API Resource in Retool

In Retool, click the Resources tab in the left sidebar and click Add Resource. Select REST API from the resource type list. Name the resource 'Jenkins API'. In the Base URL field, enter your Jenkins instance URL — for example, https://jenkins.yourcompany.com. Do not include any path after the base URL; you will specify paths in individual queries. Scroll to the Authentication section and select Basic Auth from the dropdown. In the Username field, enter your Jenkins username (the same username you use to log in to Jenkins). In the Password field, enter the API token you generated in the previous step — not your Jenkins login password. Scroll to the Headers section. Add a header with key 'Accept' and value 'application/json'. Jenkins API endpoints append /api/json to return JSON responses — you will specify this in individual query paths. Do not add the Jenkins-Crumb header in the default resource headers because crumb values expire and must be fetched fresh before each write operation. Click Save Changes. To verify the connection, create a test query in a new Retool app: set Method to GET and Path to /api/json?tree=jobs[name,url,color]. If you see your Jenkins jobs listed in the query results, the authentication is working correctly.

**Expected result:** A Jenkins API resource appears in your Retool Resources list. A test GET query to /api/json?tree=jobs[name,url,color] returns your Jenkins job list.

### 3. Query Jenkins jobs, build status, and build history

Create the core read queries for the build monitoring dashboard. In a Retool app, open the Code panel and click + to create a new query. Select your Jenkins API resource. Name the first query 'getJenkinsJobs'. Set Method to GET and Path to /api/json. Add a URL parameter 'tree' with value 'jobs[name,url,color,lastBuild[number,result,duration,timestamp,url],lastSuccessfulBuild[number,timestamp],inQueue]'. The 'tree' parameter specifies which fields Jenkins returns — this is essential for performance as Jenkins' full response can be very large. The 'color' field encodes build status: blue=success, red=failure, yellow=unstable, disabled=disabled, and the same values with '_anime' suffix for currently running builds. Add a JavaScript transformer to normalize the job data: extract name, status from color, last build result, duration (in minutes), and time since last run. Create a second query named 'getBuildDetails'. Set Method to GET and Path to /job/{{ jobsTable.selectedRow.name }}/lastBuild/api/json. Add a URL parameter 'tree' with value 'id,result,duration,timestamp,building,url,changeSet[items[commitId,msg,authorEmail]]'. This returns the last build's detailed information including changeset. Set this query to trigger when a row is selected in the jobs table.

```
// Transformer: normalize Jenkins jobs for Table display
const jobs = data.jobs || [];
return jobs.map(job => {
  const color = job.color || 'notbuilt';
  const isBuilding = color.endsWith('_anime');
  const baseColor = isBuilding ? color.replace('_anime', '') : color;
  
  const statusMap = {
    blue: 'SUCCESS',
    red: 'FAILURE',
    yellow: 'UNSTABLE',
    disabled: 'DISABLED',
    notbuilt: 'NOT BUILT',
    aborted: 'ABORTED'
  };
  
  const lastBuild = job.lastBuild || {};
  const duration = lastBuild.duration
    ? Math.round(lastBuild.duration / 60000) + 'm'
    : 'N/A';
  const since = lastBuild.timestamp
    ? Math.round((Date.now() - lastBuild.timestamp) / 3600000) + 'h ago'
    : 'Never';
  
  return {
    name: job.name,
    status: isBuilding ? 'BUILDING...' : (statusMap[baseColor] || baseColor.toUpperCase()),
    build_number: lastBuild.number ? '#' + lastBuild.number : 'N/A',
    duration,
    last_run: since,
    in_queue: job.inQueue ? 'Yes' : 'No',
    url: job.url
  };
});
```

**Expected result:** The getJenkinsJobs query returns a normalized list of Jenkins jobs with status indicators, build numbers, and timing information ready for display in a Retool Table.

### 4. Implement CSRF crumb handling for build triggering

Triggering builds in Jenkins requires CSRF crumb handling — this is the most distinctive aspect of building Retool integrations with Jenkins. Create a query named 'getJenkinsCrumb'. Set Method to GET and Path to /crumbIssuer/api/json. This endpoint returns a JSON response with two fields: 'crumbRequestField' (the header name to use, typically 'Jenkins-Crumb') and 'crumb' (the crumb value). Do not cache this query — crumbs expire and caching stale crumbs causes build trigger failures. Create a second query named 'triggerBuild'. Set Method to POST and Path to /job/{{ jobsTable.selectedRow.name }}/build. In the Headers section of this query (not the resource-level headers), add a dynamic header: set the key to {{ getJenkinsCrumb.data.crumbRequestField }} and the value to {{ getJenkinsCrumb.data.crumb }}. Set the Body to empty or to a simple JSON object {}. For parameterized builds, use the path /job/{{ jobsTable.selectedRow.name }}/buildWithParameters and add URL parameters for each build parameter. The triggerBuild query should NOT run automatically — connect it to a Button's event handler. The Button's click handler should first trigger getJenkinsCrumb and then in getJenkinsCrumb's On Success handler, trigger the triggerBuild query. This sequential chaining ensures a fresh crumb is always used. Add a Confirm Modal to the trigger button to prevent accidental build triggers in production.

```
// Parameterized build trigger configuration example
// Method: POST
// Path: /job/{{ jobsTable.selectedRow.name }}/buildWithParameters
// Header: {{ getJenkinsCrumb.data.crumbRequestField }}: {{ getJenkinsCrumb.data.crumb }}
// URL Parameters:
// ENVIRONMENT: {{ envSelect.value }}
// BRANCH: {{ branchInput.value }}
// DEPLOY_VERSION: {{ versionInput.value }}

// Alternative: POST to /buildWithParameters with form-encoded body
// Body Type: form-urlencoded
ENVIRONMENT={{ envSelect.value }}&BRANCH={{ branchInput.value }}&DEPLOY_VERSION={{ versionInput.value }}
```

**Expected result:** Clicking the 'Trigger Build' button in the Retool dashboard successfully fetches a fresh Jenkins crumb and triggers the selected job's build, showing a success notification when the build is queued.

### 5. Build the complete Jenkins operations dashboard

Assemble the full operations dashboard interface. Drag a Table component onto the canvas and set its Data to {{ getJenkinsJobs.data }}. Set getJenkinsJobs to run when the app loads. Configure columns: name (as a Text with clickable link using row.url), status (as a Tag with color mapping: SUCCESS=green, FAILURE=red, UNSTABLE=yellow, BUILDING...=blue), build_number, duration, last_run, in_queue. Below the jobs table, add a detail panel activated when a row is selected. Add a Tabs component in the detail panel with three tabs: Build Details, Console Output, and Change Log. In the Build Details tab, display the getBuildDetails query results using Statistic components for result, duration, and timestamp. In the Console Output tab, add a Text component bound to a 'getConsoleOutput' query (Method GET, Path /job/{{ jobsTable.selectedRow.name }}/lastBuild/consoleText, note: this endpoint returns plain text, not JSON — remove the /api/json suffix). Use {{ getConsoleOutput.rawData }} to access the plain text response. In the Change Log tab, display the changeSet.items array from getBuildDetails in a Table showing commit message, commit ID, and author email. Add action buttons at the top of the dashboard: 'Trigger Build' (with crumb chain), 'View in Jenkins' (opens job URL), and a 'Refresh' button that triggers getJenkinsJobs. Add a queue monitor using the endpoint /queue/api/json which shows currently queued builds. For complex Jenkins integrations with multi-branch pipelines, custom Shared Libraries, and integration with other DevOps tools in a unified internal platform, RapidDev's team can help architect and build your Retool operations dashboard.

```
// Query: Get Jenkins queue status
// Method: GET
// Path: /queue/api/json?tree=items[id,task[name],why,stuck,buildableStartMilliseconds]

// Transformer: format queue items
const items = data.items || [];
return items.map(item => ({
  queue_id: item.id,
  job_name: item.task?.name || 'Unknown',
  reason: item.why || 'Waiting',
  stuck: item.stuck ? 'Yes' : 'No',
  waiting_since: item.buildableStartMilliseconds
    ? new Date(item.buildableStartMilliseconds).toLocaleTimeString()
    : 'Unknown'
}));
```

**Expected result:** A complete Jenkins operations dashboard displays job status across all builds, build details with console output on row selection, a build queue monitor, and functional build trigger buttons with crumb-based CSRF protection.

## Best practices

- Store Jenkins API tokens in Retool Configuration Variables as secrets (Settings → Configuration Variables) rather than directly in the resource password field — this enables rotation and prevents the token from being visible in resource settings
- Always fetch a fresh Jenkins crumb immediately before each build trigger request rather than caching the crumb — crumbs expire and reusing stale crumbs causes 403 failures on build triggers
- Use Jenkins' tree parameter in every API query to limit response payload size — the full Jenkins API response for large instances can be hundreds of megabytes without tree filtering
- Add Confirm Modal dialogs to all build trigger buttons with clear messaging about the target environment — accidental production build triggers from a convenient Retool dashboard are a real operational risk
- Use a dedicated Jenkins service account for Retool API access rather than personal credentials — this ensures the integration remains functional when team members leave and makes permission auditing cleaner
- Implement Retool Workflows for polling-based build monitoring if you need real-time build status updates — schedule a Workflow to check build status every minute and send Slack notifications when status changes rather than requiring users to manually refresh the Retool dashboard
- For multi-branch pipeline jobs, query the specific branch's API URL (/job/{pipelineName}/job/{branchName}/api/json) rather than the parent pipeline's URL to get branch-specific build data

## Use cases

### Build a Jenkins build status monitor with one-click rebuild

Create a Retool dashboard that displays all Jenkins jobs with their current build status (success, failure, unstable, running) using color-coded indicators. Show the most recent build number, build duration, and time since last run for each job. Add a detail panel that displays the console output of the selected build's last run. Include a 'Rebuild' button that triggers a new build for failed or unstable jobs with crumb-based CSRF handling to ensure the build trigger succeeds.

Prompt example:

```
Build a Retool Jenkins dashboard that lists all jobs from the Jenkins API in a Table with columns for job name, last build result (color-coded: green=success, red=failure, blue=running), last build number, duration, and time since last run. When a job is selected, show the console output of the last build in a Text component. Add a 'Trigger Build' button that fetches a Jenkins crumb and then POSTs to the build endpoint.
```

### Build a parameterized deployment control panel

Create a Retool deployment operations panel that lists all Jenkins deployment jobs and provides structured forms for specifying build parameters before triggering. Support environment selection (dev, staging, production), version/branch inputs, and feature flag parameters. Add an approval workflow using Retool's permission system to restrict production deployments to authorized team members. Show recent deployment history in a Table with success/failure status and a link to the Jenkins build URL.

Prompt example:

```
Build a Retool deployment panel that shows Jenkins deployment jobs in a Select dropdown, displays their required parameters in a Form with appropriate field types (dropdowns for environment, text inputs for branch/version), and has a 'Deploy' button that fetches a Jenkins crumb and triggers the parameterized build via the Jenkins API. Show a Table of the last 10 builds for the selected job with status, trigger time, and duration.
```

### Build a CI/CD pipeline analytics and performance dashboard

Create a Retool analytics dashboard that aggregates Jenkins build data across jobs to show pipeline health metrics: build success rates by job, average build duration trends, and build failure patterns by time of day. Use Charts to visualize build frequency and failure rate over rolling 30-day windows. Combine Jenkins metrics with Git repository data (from a GitLab or GitHub Resource) to correlate code commit patterns with build failure rates.

Prompt example:

```
Build a Retool CI analytics dashboard that queries the last 50 builds from each of the top 10 Jenkins jobs, calculates success rate and average duration per job, and displays a Table sorted by failure rate. Add a Chart showing daily build success rate over 30 days for the selected job, and a second Chart showing build duration distribution.
```

## Troubleshooting

### 403 Forbidden response when triggering builds — error mentions CSRF protection or missing crumb

Cause: Jenkins' CSRF protection requires a fresh crumb value in the Jenkins-Crumb header for all POST requests. If the crumb is missing, stale (crumbs expire), or in the wrong header name (some Jenkins versions use '.crumb' instead of 'Jenkins-Crumb'), the request is rejected with 403.

Solution: Ensure the build trigger query chain fetches a fresh crumb immediately before each trigger attempt — do not cache the crumb. Verify the header name by checking the crumbRequestField value in the /crumbIssuer/api/json response and using it dynamically: set the header key to {{ getJenkinsCrumb.data.crumbRequestField }} rather than hardcoding 'Jenkins-Crumb'. If your Jenkins admin has disabled CSRF protection, you can skip the crumb step entirely.

### Jenkins API authentication works for GET requests but returns 401 for POST requests

Cause: Jenkins may have anonymous read access enabled but require authenticated write access. The Basic Auth credentials may be correct but the user account lacks the 'Build' permission required to trigger jobs.

Solution: Verify in Jenkins that your user account has the 'Job/Build' permission. In Jenkins' Security configuration (Manage Jenkins → Security → Authorization), the user needs at least: Job/Read (to view jobs), Job/Build (to trigger builds), and possibly Job/Workspace (to read console output). Ask your Jenkins administrator to grant these permissions to the API user account.

### Console output query returns binary data or garbled characters instead of readable text

Cause: The /consoleText endpoint returns plain text with Unix line endings, not JSON. If the Retool query is configured to parse the response as JSON, it fails and may display the raw bytes or an error instead of the log text.

Solution: Access the console output using {{ queryName.rawData }} instead of {{ queryName.data }} in the Text component binding. The rawData property contains the raw response string without JSON parsing attempts. Optionally, pass the rawData through a JavaScript transformer to limit it to the last N lines for very long build outputs: return data.split('\n').slice(-200).join('\n').

```
// In a Text component or transformer, use rawData for plain text endpoints:
const lines = (getConsoleOutput.rawData || '').split('\n');
// Show last 200 lines to avoid browser memory issues for large logs
return lines.slice(-200).join('\n');
```

### Job list query returns jobs but some jobs are missing from the list

Cause: Jenkins has folder-based job organization — jobs nested inside Folders or MultiBranch Pipelines do not appear in the top-level /api/json job list. The tree parameter may also be limiting the depth of nested job visibility.

Solution: For Jenkins instances with folders, use the recursive tree parameter: /api/json?tree=jobs[name,url,color,lastBuild[number,result,duration,timestamp],jobs[name,url,color,lastBuild[number,result,duration,timestamp]]]. This fetches one level of nested jobs. For deeper nesting, query specific folders directly using /job/{folderName}/api/json. Alternatively, use the Jenkins API path /view/All/api/json?tree=jobs[name,url,color,lastBuild[number,result]] which typically shows all jobs regardless of folder structure.

## Frequently asked questions

### Does Retool have a native Jenkins connector?

No, Retool does not have a native Jenkins connector. You connect using a REST API Resource with Basic Auth (Jenkins username + API token). The primary integration complexity is Jenkins' crumb-based CSRF protection for POST requests — you need to fetch a fresh crumb from /crumbIssuer/api/json and include it as a header before each build trigger request.

### How do I handle Jenkins CSRF crumb protection in Retool?

Use Retool's query chaining: create a 'getJenkinsCrumb' query (GET /crumbIssuer/api/json) and a separate 'triggerBuild' query (POST /job/{name}/build). Connect a Button's click event to trigger getJenkinsCrumb first, then in getJenkinsCrumb's On Success handler, trigger the triggerBuild query. In the triggerBuild query's Headers section, set the header key to {{ getJenkinsCrumb.data.crumbRequestField }} and value to {{ getJenkinsCrumb.data.crumb }}. This ensures every build trigger uses a fresh crumb.

### Can I trigger parameterized Jenkins builds from Retool?

Yes. Use the endpoint /job/{jobName}/buildWithParameters with POST method. Pass parameters as URL parameters (key=value pairs added to the query URL parameters section in Retool) or as a form-encoded request body. Bind parameter values to Retool form components — dropdowns for environment selection, text inputs for branch names or version numbers. Remember to include the Jenkins crumb header for this POST request as well.

### How do I read Jenkins console output in Retool?

Use the /consoleText endpoint: GET /job/{jobName}/lastBuild/consoleText. This returns plain text (not JSON), so access it using {{ queryName.rawData }} in Retool rather than {{ queryName.data }}. For large build logs, use a JavaScript transformer to show only the last N lines to avoid performance issues in the browser. Jenkins also offers a progressive console output endpoint (/progressiveText) for streaming log output during active builds.

### My Jenkins instance is behind a VPN — can Retool still connect to it?

Retool Cloud cannot connect to Jenkins instances behind a VPN without additional configuration. Options include: using self-hosted Retool deployed inside your VPN (direct network access, no additional configuration needed), setting up an SSH tunnel between Retool Cloud and your Jenkins server, or using Retool's Tunnel feature (if available on your plan) for secure connections to private networks. Check with your network team about the most appropriate approach for your security requirements.

---

Source: https://www.rapidevelopers.com/retool-integrations/jenkins
© RapidDev — https://www.rapidevelopers.com/retool-integrations/jenkins
