Set up CI uploads
Last updated 16 August 2026
Dragging a build onto a web page is fine once. Doing it after every merge, for every platform, for months, is not. Set this up instead: your CI builds the app, App Dropper gets the binary, your testers get a link — and nobody touches a browser.
Three steps, about five minutes. Everything after that is automatic.
You need one app in App Dropper first
A token grants access to apps you pick from a list, so there has to be something to pick. If you haven’t yet, upload one build from the dashboard — a one-off, per app.
1. Create an API token
Open Settings → API tokens
From the account menu in the top right of your dashboard, or go straight to the tokens page.
Click Generate token
Tick the apps this token may upload to
One, several, or all of them.
Name it after where it will live
“GitHub Actions”, “Codemagic”, “my laptop”. Then choose how long it should last — 90 days is the default.
Copy the token now
It’s shown once and never again; we store a hash, not the value. Lose it and you rotate the token to get a new one.
Tokens look like adp_a1b2c3d4e5f6g7h8i9j0_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX. Treat one like a password: anyone holding it can publish builds to the apps it covers, under your account.
What a token can do
Exactly one scope, upload:builds. That is the whole list. A leaked token cannot delete a build, remove a tester, read your billing, reach an app you didn’t tick, create new apps, or generate more tokens. The worst case is “somebody published a build to the apps this token covers” — which you undo by revoking the token and deleting the build.
How many apps to tick
For your own pipelines, tick whatever you push from that machine. One token for your laptop covering all your apps is fine, and saves re-authorising constantly.
Handing a token to someone else? Tick one app.
Publishing a build emails and push-notifies every tester on it. If a client’s repository holds the secret, a token covering all your apps turns one leaked CI log into an install prompt on every client’s testers’ phones.
You can change a token’s apps at any time from Settings → API tokens. The token value doesn’t change, so there’s nothing to update in your CI secrets. A token can never grant itself more apps; that only happens in the dashboard, while signed in.
2. Store it as a secret
Put the token in your CI provider’s secret store under the name APPDROPPER_TOKEN. Never commit it — a token in git history is a token you have to rotate.
| Provider | Where it goes |
|---|---|
| GitHub Actions | Repository → Settings → Secrets and variables → Actions |
| Codemagic | App settings → Environment variables (tick “Secure”) |
| Bitrise | Workflow Editor → Secrets |
| CircleCI | Project Settings → Environment Variables, or an Org Context |
| GitLab CI | Settings → CI/CD → Variables (tick “Masked”) |
3. Add one step to your pipeline
The command is the same everywhere. If your CI can run a shell script and has Node 18 or newer — which every mobile CI image does — this is the whole integration:
npx appdropper upload build/app/outputs/flutter-apk/app-release.apk \
--notes "$(git log -1 --pretty=%B)"The token is read from APPDROPPER_TOKEN automatically, so it never appears in your pipeline file. The command shows a progress bar while it uploads, waits for the build to be processed, prints the install link, and exits non-zero if anything fails — so a broken upload turns the build red instead of passing silently.
Pick your CI
Ready-made configuration for the usual suspects:
Using something else — Jenkins, GitLab CI, Azure Pipelines, TeamCity, a bare cron job? There’s no integration to install. Add the npx appdropper upload command above as a script step and set the environment variable. Every flag is in the CLI reference.
Where the build lands
Exactly where a dashboard upload would. App Dropper reads the name, icon, version, build number and bundle ID out of the binary, matches the bundle ID to one of your apps, files it as that app’s newest build, and emails and push-notifies its testers — the same share link and the same expiry rules as a manual upload.
Two differences worth knowing:
- If the bundle ID belongs to an app the token doesn’t cover, the upload is rejected — with a link straight to the page where you can add it.
- If no app in your account uses that bundle ID at all, it’s also rejected. Creating an app names it and starts a tester list, so it happens deliberately in the dashboard rather than silently from a pipeline.
Release notes
Whatever you pass to --notes shows up on the install page. The last commit message is the usual choice and costs nothing:
# Last commit message
--notes "$(git log -1 --pretty=%B)"
# Everything since the last tag — good for a weekly beta
--notes "$(git log $(git describe --tags --abbrev=0)..HEAD --pretty='- %s')"
# Branch and build number, when the commit messages aren't for testers
--notes "Branch $BRANCH · build $BUILD_NUMBER"Rotating a token
A token expires on the date you chose. Seven days before that we email the account owner and flag the token in your dashboard, so it shouldn’t ever be a surprise at 2am.
To replace one, hit Rotate next to it in Settings → API tokens. You get a fresh value with the same name, apps and validity window; the old one stops working immediately, so paste the new one into your CI secret in the same sitting. Rotating is also the right response to a token you think may have leaked.
Troubleshooting
“No API token”
The secret isn’t reaching the step. On GitHub Actions, secrets are withheld from workflows triggered by pull requests from forks — deliberate, on GitHub’s side. On Bitrise and Codemagic, check the variable is attached to the workflow you’re running, not just defined at app level.
Token rejected (exit code 3)
The token was revoked, has expired, or was copied incompletely. Tokens have three underscore-separated parts, and a truncated paste is the most common cause. Generate a new one and re-paste.
Token isn’t allowed to upload to that app
Often a flavour or debug variant with a suffixed bundle ID, which is a separate app as far as App Dropper is concerned. The error links straight to the token’s edit page: tick the app, save, re-run. No new token, nothing to change in your CI secrets.
No app uses that bundle ID
That app has never been uploaded. Drop the build into the dashboard once to create it, then tick it on your token and CI takes over from there.
Rate limited (exit code 4)
Each token allows 300 API requests an hour, and your plan caps uploads per hour separately (5 on free, 30 on Pro). A matrix build uploading a dozen variants per commit can reach these. The error message says how long to wait.
Uploads are slow or keep dropping
Builds go straight from your runner to Google Cloud Storage, not through our API, and a transfer resumes from where it stopped rather than restarting — so a flaky network costs you the lost chunk, not the whole 400 MB. If uploads fail consistently, check whether your runner sits behind a proxy that blocks storage.googleapis.com.
Read next
Ready to try it?
Drop an .apk or .ipa and get a shareable install link in seconds.