CI / CD guide

Fastlane integration — auto-share every IPA build

Updated May 2026 · ~6 min read

What's in this guide

If your iOS pipeline already runs Fastlane, you're 90% of the way to having every build automatically shared with your testers. This guide walks through adding the App On The Go action so that the moment gym finishes building an IPA, your testers get a fresh install link in their Slack channel.

Why integrate with Fastlane

1. Generate an API token

In your App On The Go dashboard, open Settings → API tokens and click Create token. Give it a name like "CI" so you can revoke it later if it leaks.

Tokens carry the same permissions as your account, scoped to upload + read. Treat them like passwords.

Store the token in your CI provider as a secret named AOTG_TOKEN. Every CI we've ever seen has a way to inject secrets as environment variables; the action reads from there automatically.

2. Install the Fastlane plugin

Inside your iOS project's fastlane directory, run:

fastlane add_plugin aotg

This creates (or updates) fastlane/Pluginfile with the dependency. Commit that file along with your Gemfile.lock so CI installs the same version.

3. Wire it into your Fastfile

Find your existing beta or ad-hoc lane (most teams call it :beta or :adhoc). It probably looks something like:

lane :beta do
  build_app(scheme: "App", export_method: "ad-hoc")
end

Add the aotg action after build_app:

lane :beta do
  build_app(scheme: "App", export_method: "ad-hoc")

  aotg(
    file: lane_context[SharedValues::IPA_OUTPUT_PATH],
    token: ENV["AOTG_TOKEN"],
    expiry_days: 30,
    notify_slack: true
  )
end

What each parameter does:

4. Run it

Locally first, to verify everything works end-to-end:

export AOTG_TOKEN=your_token_here
fastlane beta

Fastlane builds the IPA, the aotg action uploads it, and prints the install URL at the end of the run:

[16:21:42]: Upload complete (12.4 MB in 3.1s)
[16:21:42]: Install URL: https://i.apponthego.com/AbCdE
[16:21:42]: QR code:     https://i.apponthego.com/AbCdE.png

From here, push your changes; your CI will pick up the same lane on every build to your default branch.

Optional: Slack / webhook notifications

If you don't want to set notify_slack: true in the Fastfile, you can have the action post a generic webhook that any chat tool can consume:

aotg(
  file: lane_context[SharedValues::IPA_OUTPUT_PATH],
  token: ENV["AOTG_TOKEN"],
  webhook_url: ENV["AOTG_WEBHOOK"]
)

The payload is a small JSON blob: { url, version, build, app_name, qr_url }. Wire it into Slack incoming webhooks, Microsoft Teams, Discord, or whatever your team uses.

In GitHub Actions / Bitrise / Xcode Cloud

Same Fastlane lane, just wrapped in a CI workflow.

GitHub Actions

name: iOS beta
on:
  push:
    branches: [main]

jobs:
  beta:
    runs-on: macos-14
    steps:
      - uses: actions/checkout@v4
      - uses: ruby/setup-ruby@v1
        with:
          ruby-version: '3.2'
          bundler-cache: true
      - name: Build & share
        env:
          AOTG_TOKEN: ${{ secrets.AOTG_TOKEN }}
          MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
        run: bundle exec fastlane beta

Bitrise

Add a "Run fastlane" step to your workflow. Inject AOTG_TOKEN as a secret env. That's it — same Fastfile, no Bitrise-specific changes.

Xcode Cloud

Xcode Cloud doesn't run Fastlane natively, but you can call it from a post-build script (ci_post_xcodebuild.sh) that invokes the same lane. Same secrets injection model.

Troubleshooting

"401 Unauthorized" from the action

"IPA not found" / "File not readable"

"File exceeds plan limit"

The lane succeeds but testers report "app won't launch"

Need the API token to start? Sign in and grab one from your dashboard's Settings page.
Open dashboard →

Related reading