# Travis CI

- Tool: FlutterFlow
- Difficulty: Intermediate
- Time required: 45 minutes
- Last updated: July 2026

## TL;DR

Connect FlutterFlow to Travis CI using a FlutterFlow API Group pointing at the Travis CI API v3 (api.travis-ci.com). Authenticate every request with two required headers: Authorization using the 'token {your_token}' format and Travis-API-Version set to '3'. Pull build and repository status into a Flutter app to display a mobile CI health dashboard showing pass/fail state for every repo your team owns.

## Why connect FlutterFlow to Travis CI?

Travis CI is many teams' first continuous integration tool — it watches a GitHub repo, runs tests and builds on every push, and reports a pass or fail. The Travis CI web app shows this well for desktop, but an on-call engineer glancing at a phone during an incident wants the same overview without opening a laptop. A FlutterFlow app querying the Travis CI API v3 fills that gap: a scrollable list of repositories with green or red status chips, last-build time, and the branch that triggered the most recent run.

There are two separate reasons a founder might search 'FlutterFlow Travis CI'. The first is setting up CI for the FlutterFlow app itself: FlutterFlow can push exported Dart code to a GitHub repository, and a .travis.yml file in that repo can run flutter test and flutter build apk on every push. That config lives entirely in GitHub's web editor — there is no Travis CI setting inside FlutterFlow, and you do not need the API for this path. The second intent, and the longer tutorial, is building a mobile CI dashboard: an in-app screen that calls the Travis CI REST API to show build status for your own projects. This tutorial covers both, with the dashboard being the step-by-step walkthrough.

Travis CI's API v3 is available at api.travis-ci.com (the legacy travis-ci.org endpoint was retired in 2021 — always use .com). Authentication uses a header format specific to Travis: Authorization must be set to the literal string 'token YOUR_VALUE' (not 'Bearer YOUR_VALUE'). A second mandatory header, Travis-API-Version: 3, must accompany every request; without it the API silently falls back to legacy response shapes. Free access is available for open-source repositories; private repos require a paid credit-based plan — check current pricing on travis-ci.com.

## Before you start

- A Travis CI account at travis-ci.com with at least one GitHub repository connected
- A Travis CI API token generated from your account Settings page (Settings → API Authentication)
- Your GitHub organization or username slug (used in API paths like /owner/{slug}/repos)
- A FlutterFlow project with the API Calls panel accessible
- For shared or published apps: a Firebase project or Supabase project to host the proxy Cloud Function

## Step-by-step guide

### 1. Generate your Travis CI API token and understand the two required headers

Open travis-ci.com in a browser and sign in. Click your profile picture or name in the top-right corner and choose Settings from the dropdown. Scroll down to the API Authentication section. If a token already exists, copy it using the Copy button. If none exists, click Generate a new token, give it a name like 'FlutterFlow Dashboard', and copy the generated string — it is typically a 22-character alphanumeric value. Store this token somewhere safe such as a password manager, because Travis CI will not show it again after you navigate away.

Travis CI's API v3 requires two specific headers on every single request. Miss either one and the call fails or returns unreadable data. The first header is Authorization — its value must be the literal string 'token ' (the word token, a space) followed by your token string. This is NOT the Bearer format used by most modern APIs; sending 'Bearer YOUR_TOKEN' returns a 403 error. The second required header is Travis-API-Version with the value '3'. Without this header the API responds in a legacy v2 format whose response structure is completely different from what the current docs describe, and your JSON Path mappings in FlutterFlow will not match anything.

Also note your GitHub owner slug — this is the GitHub username or organization name that appears in your repository URLs (github.com/{owner}/{repo}). Travis CI's API uses the same slug for paths like /owner/{slug}/repos to list all repositories for that owner. Case-sensitive and must match exactly. Write it down alongside your token before moving to FlutterFlow.

**Expected result:** You have a Travis CI API token, know that Authorization must use the 'token ' prefix (not 'Bearer'), and know your GitHub owner slug. You are ready to configure the API Group in FlutterFlow.

### 2. Create the FlutterFlow API Group with both required headers

In FlutterFlow, click API Calls in the left navigation panel. Click the + Add button and choose Create API Group. In the Group Name field enter 'Travis CI'. In the Base URL field enter https://api.travis-ci.com — this is the only valid Travis CI API v3 host. Do not add a trailing slash.

Now add the two mandatory headers at the group level so they are sent automatically on every call in this group. Scroll to the Headers section and click Add Header twice. First header: set the Key to Travis-API-Version and the Value to 3 (the digit three, as a string). Second header: set the Key to Authorization and the Value to token YOUR_TRAVIS_TOKEN — replace YOUR_TRAVIS_TOKEN with your actual token, keeping the word 'token' and the space before it. The header value should look like: token abcdefghij1234567890xy.

A note on token security: for a personal tool you alone use, storing the token directly in the API Group header is acceptable for quick testing. However, the Travis CI API token is account-scoped — it can read all build logs and repository metadata for your GitHub organization. For any app you share with colleagues or publish to an app store, this token must move to a Firebase Cloud Function or Supabase Edge Function proxy (see Step 3 in the 'shared app' path below). For now, click Save Group to proceed with the direct setup and test connectivity.

To verify the group is working: click + Add inside the Travis CI group, choose Create API Call, name it 'Get User', set the method to GET and the path to /user. Click Test API Call. The response should return a JSON object with your Travis CI user id and login — confirming both required headers are accepted.

```
{
  "group_name": "Travis CI",
  "base_url": "https://api.travis-ci.com",
  "headers": [
    { "key": "Travis-API-Version", "value": "3" },
    { "key": "Authorization", "value": "token YOUR_TRAVIS_TOKEN" }
  ]
}
```

**Expected result:** The Travis CI API Group is saved in FlutterFlow. A test GET /user call returns your Travis CI user profile JSON, confirming both the Authorization and Travis-API-Version headers are working correctly.

### 3. (Shared apps) Deploy a Cloud Function proxy to secure the Travis CI token

Skip this step if you are building a personal tool only you will use. For any app shared with team members or published publicly, the Travis CI API token must never ship inside the FlutterFlow client binary — any user can extract headers from a compiled Flutter app with basic reverse-engineering tools. The solution is a thin Firebase Cloud Function (or Supabase Edge Function) that holds the token server-side and exposes only the safe read operations your app needs.

In the Firebase Console, navigate to your project and click Functions → Get Started (or open an existing functions project). In the Cloud Functions code editor or your local functions folder, create the proxy as a Node.js HTTPS function. The function receives calls from FlutterFlow, adds the Travis CI token from environment variables, and forwards the request to the appropriate Travis CI endpoint. Deploy it with Firebase CLI or the Firebase Console's inline editor. After deploying, copy the function's HTTPS URL — it will look like https://us-central1-your-project.cloudfunctions.net/travisCiProxy.

Back in FlutterFlow, update the Travis CI API Group's Base URL to point at your deployed proxy URL instead of https://api.travis-ci.com. Remove the Authorization header from the FlutterFlow API Group — the proxy adds it server-side. The Travis-API-Version header can stay in FlutterFlow (it is not a secret). From this point forward all Travis CI API calls flow through your proxy, and the token never leaves your Cloud Function environment.

```
// Firebase Cloud Function: travisCiProxy/index.js
const functions = require('firebase-functions');
const fetch = require('node-fetch');

// Set the token: firebase functions:config:set travis.token="YOUR_TOKEN"
const TRAVIS_TOKEN = functions.config().travis.token;
const TRAVIS_BASE = 'https://api.travis-ci.com';

exports.travisCiProxy = functions.https.onRequest(async (req, res) => {
  // CORS for FlutterFlow web builds
  res.set('Access-Control-Allow-Origin', '*');
  res.set('Access-Control-Allow-Methods', 'GET, OPTIONS');
  res.set('Access-Control-Allow-Headers', 'Content-Type');
  if (req.method === 'OPTIONS') { res.status(204).send(''); return; }

  // Only allow safe read routes
  const allowedPaths = ['/user', '/repos', '/builds', '/owner'];
  const path = req.path || '/';
  const isSafe = allowedPaths.some(p => path.startsWith(p));
  if (!isSafe) { res.status(403).json({ error: 'Path not allowed' }); return; }

  const url = `${TRAVIS_BASE}${path}${req.url.includes('?') ? req.url.substring(req.url.indexOf('?')) : ''}`;
  const travisRes = await fetch(url, {
    headers: {
      'Authorization': `token ${TRAVIS_TOKEN}`,
      'Travis-API-Version': '3',
      'Content-Type': 'application/json'
    }
  });
  const data = await travisRes.json();
  res.status(travisRes.status).json(data);
});
```

**Expected result:** The Cloud Function is deployed and accessible at an HTTPS URL. Calling it from a browser with a valid path returns Travis CI JSON. The FlutterFlow API Group now points at the proxy URL, and the token is no longer stored in any FlutterFlow field.

### 4. Add the Get Repositories and Get Builds API Calls

Inside the Travis CI API Group, click + Add → Create API Call. Name it 'Get Repositories'. Set method to GET. In the Path field enter /owner/{{ owner_slug }}/repos — then click the Variables tab and add a String variable named owner_slug with a default value set to your GitHub username or org name. Add two Query Parameters: limit set to 100 (to get up to 100 repos in one call) and include set to repo.last_build (this embeds the latest build details inside each repository object, saving you a second API call). Click Save.

In the Response & Test tab, click Test API Call. After a successful response, FlutterFlow shows the raw JSON. Click Generate JSON Paths — this auto-creates path bindings from the response structure. The important paths are: $.repositories[*].name (repo name), $.repositories[*].slug (repo slug for further calls), $.repositories[*].last_build.state (passed / failed / errored / canceled), $.repositories[*].last_build.started_at (timestamp), and $.repositories[*].last_build.duration (build time in seconds).

Create a second API Call inside the same group: name it 'Get Builds'. Set method to GET, path to /repo/{{ repo_slug }}/builds. In the Variables tab add a String variable repo_slug. Add Query Parameter limit set to 25. In the Response & Test tab, supply a repo slug in format 'owner%2Frepo-name' (the slash URL-encoded as %2F) and click Test. Generate JSON Paths: the key paths are $.builds[*].state, $.builds[*].number, $.builds[*].duration, $.builds[*].branch.name, $.builds[*].started_at.

Both calls are now ready to bind to widgets.

**Expected result:** Both API Calls are saved in the Travis CI group. 'Get Repositories' returns an array of repos with last_build nested inside each. 'Get Builds' returns a list of recent builds for a specific repo. JSON Paths are generated and visible in FlutterFlow's response mapping.

### 5. Build the CI dashboard ListView with pass/fail status coloring

Open the FlutterFlow page where you want the CI dashboard. Add a Backend Query to the page using the Get Repositories API Call — set the owner_slug variable to your org slug. This fetches the repo list when the page loads.

Add a ListView widget to the page. Inside it, place a Container (one list item). Inside the Container add a Row with three children: a status indicator (Icon or Container with conditional background color), a Column for the repo name and branch text, and a Text widget showing how long ago the last build ran.

For the status color, select the status Container and open the Conditional Logic panel. Add a condition: if the $.repositories[*].last_build.state JSON Path value equals 'passed', set the background color to green. Add a second condition: if the value is 'failed' or 'errored', set background color to red. For all other states (created, started, canceled), use amber/orange.

Bind the repo name Text widget to $.repositories[*].name and the branch Text widget to $.repositories[*].last_build.branch.name via the JSON Path set during testing.

Add a Pull To Refresh action to the ListView: open the Actions panel on the ListView, click + Add Action → Utilities → Refresh Page or re-run the Backend Query on pull. This lets users swipe down to re-fetch fresh build status.

For navigation to the per-repo build list: select the Container (list item) and add an On Tap action → Navigate to a detail page. Pass the repo slug as a page parameter. On the detail page, use the Get Builds API Call with the passed slug and show a second ListView of recent builds with the same pass/fail coloring pattern.

If you would rather skip the custom response-mapping and have RapidDev's team wire this up for you, a free scoping call is available at rapidevelopers.com/contact.

**Expected result:** The page loads a ListView of Travis CI repositories. Each row shows a green, red, or amber status chip alongside the repo name and branch. Pull-to-refresh re-fetches the list. Tapping a row opens a detail page with the last 25 builds for that repo.

### 6. Add the .travis.yml CI pipeline for the FlutterFlow app itself (optional)

This step covers the other common intent: running Travis CI on the FlutterFlow-exported Flutter code, so every push to GitHub triggers automated flutter test and flutter build apk runs. No Travis CI setting lives inside FlutterFlow — this configuration lives in the GitHub repository that FlutterFlow exports to.

In FlutterFlow, go to Settings → Integrations → GitHub and connect your GitHub account if you have not already. Click Export to GitHub. FlutterFlow creates a branch in the connected repository with the exported Dart/Flutter project.

Open github.com and navigate to the exported repository. Click Add File → Create New File. Name the file .travis.yml (the dot is part of the name). Paste the configuration shown in the Code field below. This tells Travis CI to use Ubuntu, install the Flutter SDK, run flutter pub get to fetch dependencies, run flutter test to execute your unit tests, and (optionally) run flutter build apk --release to confirm the release build compiles. Commit the file directly to the main branch.

In the Travis CI web interface at travis-ci.com, navigate to your repository (if it does not appear, click your profile → Sync Account to refresh). Travis CI should automatically detect the .travis.yml and trigger a build within a minute or two. The build log shows each command running and exits with success (green) or failure (red). Future FlutterFlow exports that push to this repo will automatically trigger a new Travis CI build.

```
# .travis.yml — Add to the root of your FlutterFlow-exported GitHub repo
language: generic
os: linux
dist: focal

env:
  global:
    - FLUTTER_VERSION=stable
    - ANDROID_SDK_ROOT=$HOME/android-sdk

before_install:
  - git clone https://github.com/flutter/flutter.git -b $FLUTTER_VERSION --depth 1 $HOME/flutter
  - export PATH=$PATH:$HOME/flutter/bin:$HOME/flutter/bin/cache/dart-sdk/bin
  - flutter doctor -v

install:
  - flutter pub get

script:
  - flutter test
  # Uncomment to also build the APK on every push:
  # - flutter build apk --release
```

**Expected result:** Travis CI picks up the .travis.yml from the GitHub repository and runs a build. The Travis CI dashboard shows a new build in progress. After a few minutes it shows green (passed) if the flutter test step passes, or red if any test fails. Future pushes automatically trigger new builds.

## Best practices

- Always add both Travis-API-Version: 3 and Authorization: token {token} at the API Group level rather than per-call — missing either header on any single call will cause silent format failures or 403 errors.
- Use 'token ' (not 'Bearer ') as the Authorization prefix — Travis CI has its own auth convention that differs from standard OAuth2 Bearer syntax and will reject the Bearer format with a 403.
- For apps shared with more than one person, proxy the Travis CI token through a Firebase Cloud Function — a user-scoped Travis CI token exposes all build logs and repository metadata for your entire GitHub organization.
- Scope the proxy whitelist to read-only endpoints (/repos, /builds, /user) and explicitly block write endpoints (/builds POST to trigger builds) unless your app genuinely needs that capability.
- Store the encoded repo slug (owner%2Frepo-name) rather than the raw slug in App State when you navigate to a per-repo detail screen — this avoids 404 errors from unencoded forward slashes in API path segments.
- Add the include=repo.last_build query parameter to the /repos call so the last build state is embedded in each repository object, avoiding a separate API call per repo when rendering the list.
- Use pull-to-refresh on the repository ListView rather than auto-polling on a timer — Travis CI does not publish rate limits but polling every few seconds from multiple devices on the same token is wasteful and unnecessary for a read dashboard.
- For the .travis.yml CI pipeline, pin the Flutter version to 'stable' in the clone command rather than a hard-coded version number so the build picks up Flutter stable channel updates automatically.

## Use cases

### Mobile CI health dashboard for a development team

Build a FlutterFlow app screen that lists all your team's GitHub-connected Travis CI repositories with their last build status, last run time, and branch name. Each row shows a green or red status chip driven by the build 'state' field. On-call engineers can check CI health from their phone without opening a browser or laptop. A pull-to-refresh gesture re-queries the API so the view stays current during an active incident.

Prompt example:

```
A CI dashboard screen with a ListView of repository cards. Each card shows the repo name, a green 'Passing' chip or red 'Failing' chip based on the last build state, the branch name, and how long ago the last build ran. Tapping a card navigates to a detail screen showing the last 10 builds for that repo with their durations and commit message.
```

### Build notification app for a solo indie developer

A lightweight FlutterFlow personal app that shows the last 5 builds across all your repositories with pass/fail state and duration. Because you own the app and share it with no one, the Travis CI token can live in a Custom App Value for simplicity. The home screen refreshes on open so the most recent build result is always front and center, replacing the need to check the Travis CI website after each GitHub push.

Prompt example:

```
A personal mobile app home screen showing my 5 most recent Travis CI builds across all repos. Each item shows repo name, build number, pass or fail icon, branch, and duration in minutes and seconds. Tapping a build shows the raw build state and commit SHA.
```

### CI status screen embedded in an engineering ops app

Add a Travis CI status tab to an existing FlutterFlow operations app that already shows deploys, error rates, or on-call schedules. The tab pulls repositories and last-build state from the Travis CI API and surfaces only failing builds, giving an ops engineer a single place to see everything broken right now. A Cloud Function proxy keeps the Travis CI token server-side since the app is used by multiple team members.

Prompt example:

```
An 'Alerts' tab in an existing ops FlutterFlow app. Query the Travis CI API via a Cloud Function proxy and show only repositories whose last build state is 'failed' or 'errored'. Display repo name, failing branch, and time since the failure. Empty state message when all builds are passing.
```

## Troubleshooting

### API returns 403 Forbidden or 'access denied' message when calling any Travis CI endpoint

Cause: The Authorization header is using the wrong format — Travis CI requires 'token YOUR_VALUE' (lowercase word 'token' followed by a space and the token string), not the more common 'Bearer YOUR_VALUE' format used by most OAuth2 APIs.

Solution: In the FlutterFlow API Group headers, find the Authorization entry and confirm its value starts with the word 'token ' (with a space) and NOT 'Bearer '. Change it to: token abcdefghij1234567890xy (your actual token after the space). Also confirm the Travis-API-Version header is present with value '3'. Test with a GET call to /user — a 200 response with your user object means both headers are correct.

### Response JSON has unexpected structure — no 'repositories' or 'builds' array where the docs say it should be

Cause: The Travis-API-Version: 3 header is missing. Without it the Travis CI API falls back to its legacy v2 response format, which wraps data differently and omits fields present in v3.

Solution: Open the Travis CI API Group in FlutterFlow's API Calls panel and verify the Travis-API-Version header exists with the value '3' (the digit, as a string). Add it at the group level so it is sent with every call. Re-run the test call and regenerate JSON Paths from the corrected response structure.

### GET /repo/{slug}/builds returns a 404 Not Found even though the repo exists in Travis CI

Cause: The repository slug contains a forward slash (owner/repo-name) which is a URL path separator. When passed unencoded in a path segment, the API interprets it as two separate path components and cannot find the resource.

Solution: URL-encode the forward slash in the slug: replace the '/' between owner and repo name with '%2F'. For example, 'my-org/my-app' becomes 'my-org%2Fmy-app'. In FlutterFlow, store the encoded slug in the variable passed to the repo_slug variable on the Get Builds API Call. Alternatively, use the numeric repository id (available from the repos list response as repo.id) in the path /repo/{id}/builds — numeric IDs never have encoding issues.

### The .travis.yml build triggers on GitHub pushes but the Flutter tests fail immediately with 'flutter: command not found'

Cause: The Travis CI build environment does not have Flutter pre-installed. The .travis.yml must clone the Flutter SDK and add it to PATH in the before_install section before any flutter commands can run.

Solution: Verify the .travis.yml includes the before_install block that clones the Flutter repository from GitHub and exports its bin directory to PATH. The flutter doctor -v line at the end of before_install confirms the SDK is active. Check the Travis CI build log — if the clone command fails, confirm the Travis CI build has internet access (it does by default on travis-ci.com). If you see 'Permission denied' on flutter binary, add 'chmod +x $HOME/flutter/bin/flutter' after the clone.

## Frequently asked questions

### Does the Travis CI integration I build in FlutterFlow run CI on my FlutterFlow app's code, or does it read CI results from an existing repo?

Both are possible but separate setups. To run CI on your FlutterFlow app: export the code to GitHub and add a .travis.yml to that repo — Travis CI then builds it automatically on each push (see Step 6). To read Travis CI build results from inside a FlutterFlow app: configure the API Group from Steps 2 and 4 to query travis-ci.com and display status in a ListView — this is a monitoring dashboard, not a trigger for your own builds.

### Why do I need the Travis-API-Version: 3 header? Can I leave it out?

No. Without the Travis-API-Version: 3 header, the Travis CI API silently returns responses in its legacy v2 format, which wraps data differently and omits fields present in v3. Your FlutterFlow JSON Path bindings ($.repositories[*].name, $.builds[*].state, etc.) will not find the expected fields and your widgets will show empty data. Always include this header at the API Group level.

### Is the Travis CI API token safe to put directly in a FlutterFlow API Group header?

For a personal internal tool that only you use and never publish to an app store, it is acceptable for prototyping. For any app installed on multiple devices or submitted to the App Store or Play Store, the answer is no — Flutter app binaries can be reverse-engineered and headers extracted. The token is account-scoped and exposes all build logs and repo metadata for your GitHub organization. Route it through a Firebase Cloud Function proxy as shown in Step 3.

### Travis CI has both travis-ci.com and travis-ci.org — which one should I use?

Always use travis-ci.com. The .org domain hosted only free open-source builds and was permanently shut down in June 2021. All builds — both public and private repositories — now run on travis-ci.com. The correct API base URL is https://api.travis-ci.com. Any tutorial or API reference pointing to .org is outdated and the endpoints no longer respond.

### Can I trigger a Travis CI build from a button in my FlutterFlow app?

Yes, but only with extra care. Travis CI's API v3 supports POST /repo/{slug}/requests to trigger a new build. However, this is a write operation and requires your token to have appropriate permissions. You must also proxy it through a Cloud Function (never expose a write-capable token in the FlutterFlow client). Add a confirmation dialog in FlutterFlow before sending the trigger request to prevent accidental builds.

---

Source: https://www.rapidevelopers.com/flutterflow-integrations/travis-ci
© RapidDev — https://www.rapidevelopers.com/flutterflow-integrations/travis-ci
