7min read

How to Create a Seamless TestFlight Integration

All companies struggle with a way to distribute its products to clients. Distribution has to be safe, fast and reliable. It applies to software companies too— we need a platform to provide our digital/software products to clients. Some time ago on our blog we’ve described how we use our in-house app called Shuttle. It allows to provide builds on iOS and Android, search through previously published builds and incorporate both types of users (clients and developers) thanks to different possible access levels.

In today’s blog post we will discuss a solution for the automatic distribution of new versions of an app to a client for iOS developers through TestFlight—a platform recommended by Apple.

Our take on TestFlight

We wouldn’t be ourselves if we didn’t add some twist to the TestFlight tool. In Polidea we are all about making our work easier. The first time we had to set up TestFlight beta tests we started figuring out how to make it more automatic. In the ideal world it would be easy to maintain. Once a developer sets up a whole process he will not have to remember about having TestFlight in his build pipeline at all! That led us to think about more requirements we would like to meet. TestFlight app has to be connected to Apple Developer Program, preferably client’s program so he could manage a number of testers, date of the test releases and of course when an app is ready and can go live. That means we would have to manage client’s certificates and credentials aka the sensitive data. But how to do it safely and give the control to the client?


The solution

We came to the following conclusion. The main idea is to leave control and responsibility for protecting client’s resources on the client’s side. That is why we create new AppleID and connect it to the client’s Apple Developer Program (they can remove an account from the program at any time by denying access to resources). A client creates an account with access to the certificates repository with a setup SSH connection to Polidea (client can remove SSH connection denying us access to the repository). That leave us with hosting of certificates by the client (he/she is responsible for who has access to the repository with certificates).

But… but, how?

How to do it? First of all there are some requirements you need to have set up on the computer.

  • Fastlane
  • Match
  • Admin account for gitlab repository containing project

We will focus on using Gitlab and Gitlab CI only but these setup could be reproduced on any other hosting service with small modifications. First things first, we need to prepare some basics before we trouble a client with some actions on his or her side.

  1. Generate ssh keys.

    1. Add a private key as a secret variable under SSH_PRIVATE_KEY name in the project’s gitlab repository.
  2. Create a new mailing group marked as a TEAM and connect all the accounts of project members with an enabled option “Allow to post emails from Internet”. This will allow everyone to respond when something happens and a person setting TestFlight would be on vacation.

  3. Create AppleID for the created group account and save credentials in such a way they are shared securely.

Now we can ask our client to set everything up on his side.

  1. Ask the client to create a repository for certificates (for example “iOS-certificates”).
  2. Ask the client to create new gitlab account which will have read & write access level to previously created repository.
  3. Ask the client to add created in the the 1st step public ssh key to the newly created gitlab account.
  4. Ask the client to add the created in 3rd step AppleID to client’s Apple Developer Program.
  5. Ask the client to create new AppID (for example #PRODUCT_APPID#) on the Apple Developer Platform.

Now if everything goes well we should have access to the repository with certificates and our AppleID should be properly connected with the client’s Apple Developer Program. But as you can see the repository is empty. This is a step where fastlane and match come in handy. Right now only the client has the distribution certificate and private key stored in keychain. Because of that he has to generate certificates in the previously created repository.

  1. Run command

    fastlane match appstore --git_url "" --app_identifier "#PRODUCT_APPID#" --readonly false 

Remember to save passphrase which was provided to fastlane while this command executes. Passphrase is the only password to decrypt those files. Now the script will create proper provisioning profile and distribution certificate on Apple Developer Program. It will allow us to upload builds signed with those certificates to the AppStoreConnect. Next it will save all needed files under “git_url” parameter indicated repository.

Consider the risks

Some would say it is dangerous to reside all keys, certificates and provisioning profiles in the repository and they are right. That is why we suggest using a private repo also notice that Match additionally encrypt files with SHA-256. At the end of the day remember that an attacker who has these files probably won’t do much harm. All certificates can be revoked, denying attacker from further exploit of client’s resource. Answers to more detailed questions can be found in the match manual in the section “Is this secure?”.

Wrap it up

At this point all the steps that needed to be done by the client are done. You should be able to have access through Apple Developer Platform to all the Provisioning Profiles.

  1. Add passphrase as a secret variable under MATCH_PASSWORD name on the project’s gitlab repository.

Note: Secret variables are injected to the Gitlab CI runners during build time. It is common to store in them private keys and passwords. Thanks to that in fastfile you can call just an environment parameter and there is no need to store password within code in repository.

  1. Add password to AppleID as a secret variable under FASTLANE_PASSWORD so Match could login to iTunesConnect with proper account which is able to push new builds.
  2. Create new target in your project (for example #PRODUCT#Prod).

    1. Set there a proper appID (“#PRODUCT_APPID#),
    2. Download corresponding Provisioning Profile and set it in a newly created target.

Regarding step 12, as well as a new target you can create a new scheme that would be build on CI preferably for you project management strategy. The only thing left is to set up the pipeline to automatically build new versions and upload to TestFlight. Thanks to the fastlane it’s super easy. First, we need to match certificates from the client’s repository to our account with access to the client’s Apple Developer Program.

  1. Add fastlane match in Fastfile to match against client’s repo with certificates.

    def match_#PRODUCT#
    type: "appstore",
    git_url: "ssh://",
    app_identifier: "#PRODUCT_APPID#",
    username: "",
    readonly: true
  2. Add a new lane to create TestFlight build. It needs to build the app in a newly created target so the provisioning profiles from the previous step will match. Secondly, we create fastlane’s testflight action to upload the app to TestFlight.

    desc "Deploy Release via TestFlight"
    lane :deployToTestFlight do
            scheme: "#PRODUCT#Prod",
            include_symbols: false,
            xcargs: "DEBUG_INFORMATION_FORMAT=dwarf-with-dsym
            username: "",
            app_identifier: "#PRODUCT_APPID#"

    The last step is to provide gitlab instructions on when and how to deploy the app to TestFlight. At Polidea we publish builds per tag. This is how we will do it here. Also you must remember that the certificates are in the repository hosted by the client so CI’s machine has to know proper SSH key to connect with it.

  3. Add new stage in .gitlab-ci.yml. before the script SSHPRIVATEKEY is added to machine so it could connect to repository with certificates via client’s account.

    stage: deploy
       - eval $(ssh-agent -s)
       - echo "$SSH_PRIVATE_KEY" >~/.ssh/#PRODUCT#_key && chmod 600 ~/.ssh/#PRODUCT#_key
       - ssh-add ~/.ssh/#PRODUCT#_key
       - ssh-keyscan -H >> ~/.ssh/known_hosts
       - bundle exec fastlane deployToTestFlight
       - tags

    And Voila! That’s all! Next time you set a tag, a new version will be uploaded to TestFlight. The last thing is to log in to App Store Connect and publish it. The best thing about this solution is that since it is already the client’s Apple Developer Program he can autonomously decide which build provide to testers or publish for himself to check.

Where to search for more?

Fastlane is a complicated tool with many options. For more advanced usage go here:


BartoszSenior Software Engineer


Sign in and expect sharp insights, recommendations, ebooks and fascinating project stories delivered to your inbox

The controller of the personal data that you are about to provide in the above form will be Polidea sp. z o.o. with its registered office in Warsaw at ul. Przeskok 2, 00-032 Warsaw, KRS number: 0000330954, tel.: 0048 795 536 436, email: (“Polidea”). We will process your personal data based on our legitimate interest and/or your consent. Providing your personal data is not obligatory, but necessary for Polidea to respond to you in relation to your question and/or request. If you gave us consent to call you on the telephone, you may revoke the consent at any time by contacting Polidea via telephone or email. You can find detailed information about the processing of your personal data in relation to the above contact form, including your rights relating to the processing, HERE.

Data controller:

The controller of your personal data is Polidea sp. z o.o. with its registered office in Warsaw at ul. Przeskok 2, 00-032 Warsaw, KRS number: 0000330954, tel.: [0048795536436], email: [] (“Polidea”)

Purpose and legal bases for processing:


Used abbreviations:

GDPR – Regulation (EU) 2016/679 of the European Parliament and of the Council of 27 April 2016
on the protection of natural persons with regard to the processing of personal data and on the free movement
of such data, and repealing Directive 95/46/EC (General Data Protection Regulation)

ARES – Polish Act on Rendering Electronic Services dated 18 July 2002

TL – Polish Telecommunications Law dated 16 July 2004

1)        sending to the given email address a newsletter including information on Polidea’s new projects, products, services, organised events and/or general insights from the mobile app business world |art. 6.1 a) GDPR, art. 10.2 ARES and art. 172.1 TL (upon your consent)

Personal data:name, email address

2)       statistical, analytical and reporting purposes |art. 6. 1 f) GDPR (based on legitimate interests pursued by Polidea, consisting in analysing the way our services are used and adjusting them to our clients’ needs, as well as developing new services)

Personal data:name, email address

Withdrawal of consent:

You may withdraw your consent to process your personal data at any time.

Withdrawal of the consent is possible solely in the scope of processing performed based on the consent. Polidea is authorised to process your personal data after you withdraw your consent if it has another legal basis for the processing, for the purposes covered by that legal basis.

Categories of recipients:

Your personal data may be shared with:

1)       authorised employees and/or contractors of Polidea

2)       persons or entities providing particular services to Polidea (accounting, legal, IT, marketing and advertising services) – in the scope required for those persons or entities to provide those services to Polidea


Retention period:

1)       For the purpose of sending newsletter to the given email address – for as long as the relevant consent is not withdrawn

2)       For statistical, analytical and reporting purposes – for as long as the relevant consent is not withdrawn

Your rights:


Used abbreviation:

GDPR – Regulation (EU) 2016/679 of the European Parliament and of the Council of 27 April 2016
on the protection of natural persons with regard to the processing of personal data and on the free movement
of such data, and repealing Directive 95/46/EC (General Data Protection Regulation)

According to GDPR, you have the following rights relating to the processing of your personal data, exercised by contacting Polidea via [e-mail, phone].

1)       to access to your personal data (art. 15 GDPR) by requesting sharing and/or sending a copy of all your personal data processed by Polidea

2)       to request rectification of inaccurate personal data
(art. 16 GDPR) by indicating the data requiring rectification

3)       to request erasure of your persona data (art. 17 GDPR); Polidea has the rights to refuse erasing the personal data in specific circumstances provided by law

4)       to request restriction of processing of your personal data (art. 18 GDPR) by indicating the data which should be restricted

5)       to move your personal data (art. 20 GDPR) by requesting preparation and transfer by Polidea of the personal data that you provided to Polidea to you or another controller in a structured, commonly used machine-readable format

6)       to object to processing your personal data conducted based on art. 6.1 e) or f) GDPR, on grounds relating to your particular situation (art. 21 GDPR)

7)       to lodge a complaint with a supervisory authority,
in particular in the EU member state of your habitual residence, place of work or place of the alleged infringement if you consider that the processing
of personal data relating to you infringes the GDPR
(art. 77.1 GDPR)

No obligation to provide data:

Providing your personal data is not obligatory, but necessary for Polidea to provide you the newsletter service

Refusal to provide the above data will result in inability to receive the newsletter service.


In the process of providing the newsletter service, we make decisions in an automated way, including profiling, based on the data you provide.


“Profiling” means automated processing of personal data consisting of the use of your personal data to evaluate certain personal aspects relating to you, in particular to analyze or predict aspects concerning your personal preferences and interests.


The automated decisions are taken based on the analysis of clicked and viewed content. They affect the targeting of specific newsletter content to selected users registered to receive the newsletter service, based on the anticipated interests of the recipient.