When: Sunday, April 30 at 3PM PST (Sunday, April 30 at 22:00:00 UTC)

Estimated downtime: 20 minutes

Continuing our efforts to bring you a faster more stable TestFlight we are migrating the primary TestFlight database to new bare metal hardware.

This system maintenance should result in less than 20 minutes downtime.  The procedure is to lock the current database to prevent writes, swap the host records and DNS, and rejoice.

This beefier setup will also give us additional capacity to begin the next round of improvements that we are making to the overall system architecture and infrastructure.

Thanks,

TestFlight Crew

We are introducing production SDK rate limiting in an effort to address stability across TestFlight. Our goal is to give ourselves a little air cover while we work to improve overall scalability.

This will not have any impact on your application or your users. If your app starts to skyrocket on the charts, you can simply request a rate limit increase from the notification area.

When SDK traffic hits the TestFlight servers we detect if the traffic was from a production application or a beta application. In the event that your production traffic crosses a particular threshold TestFlight will stop processing the inbound data. The initial SDK always included this functionality, but up until now it was only used to remotely disable the SDK upon developer request.

The limits themselves are dynamic based on how you currently use the service.  An example, TestFlight Live users have higher limits than non TestFlight Live users. We tried our best to implement limits that would have the least impact on the current level of use.

This is one step we are taking to ensure TestFlight can continue to grow without having a negative effect on our users and your users. Again, our goal is to provide a little air cover since we are hard at work improving stability throughout the entire site. We appreciate your understanding and we look forward to lifting the rate limit soon. If you have any questions or concerns please let us know.

Thanks,

TestFlight Crew

We usually love Mondays, but today was an exception. We apologize for the downtime. It was unexpected. There was maintenance scheduled for today at 12 AM PST. This should have resulted in minimal service interruption. Unfortunately it turned into a 6 hour recovery of our primary database.  

In short, pacemaker sigkilled MySQL caused massive corruptions (fortunately no data loss). Due to the extended length of downtime the SDK message queues backed up to the point where we OOMd (resulting in SDK data loss). The team worked through the night to correct the issues. It’s become our priority to move towards architecture and infrastructure changes that will prevent this from happening again.

We have been heads down trying to improve the service but need to make sure we communicate with you asap when something goes wrong. We should have done a better job with this today as well.  

Thank you for continuing to help TestFlight grow.  We can’t apologize enough for the issues of late, we are working as fast as we can to resolve them.

Today TestFlight will be switching everyone over to our new UI. A lot of elbow grease went into the new polish, while keeping the great features you expect from us. We’re investing more resources into these tools so it will grow to meet everyone’s needs.

Some of you may have already experienced the new UI as you ventured over to account settings and flipped on the v2 switch in Area51. Kudos to everyone’s curiosity and excellent feedback!

For those of you who haven’t seen the new UI, you’ll see a few notable changes:

  • Build options can be accessed by selecting the build of your choice from the build table
  • Build history can be accessed by clicking on the More button for apps with multiple builds
  • Once in build context, find your way back with a helpful breadcrumb to give you context as you navigate between apps
  • Managing your teams and testers got an overhaul with user details now launching into a modal window. Manage your users, distribution lists, and invites just as you did before






We’re excited about these improvements and hope you find them valuable.
Thanks again for all your support and great feedback. Please continue to share that with us. Enjoy your next flight.

- the TestFlight crew

By now you’re probably aware that Apple has started to reject applications that access the UDID. The only reason that the TestFlight SDK accesses the UDID is to provide the best possible information about your testers. When we made the decision to provide a single SDK for beta testing and production applications we did so because we want your beta and release builds to have as close to the same code base as possible. Now that the UDID is no longer allowed in production applications we will still continue to use a single SDK for both Beta testing and Live releases.

In order to accomplish the goal of a single SDK for all release types we have introduced a new method into the SDK, +setDeviceIdentifier:(NSString)deviceIdentifier. This method is always optional and never needs to be set. However, we feel that during beta testing most of you would like to see which members of your team have seen and tested which parts of your applications. To enable that we allow you to use the +setDeviceIdentifier:(NSString)deviceIdentifier method to set the device unique identifier. We recommend that when you choose to set +setDeviceIdentifier:(NSString)deviceIdentifier to the current device’s unique identifier that you wrap the method in a preprocessor directive that only enables the call when you are building for ad-hoc release.

For further information and code samples please see our online documentation. If you decide that you do not wish to set +setDeviceIdentifier:(NSString)deviceIdentifier, we will still collect all of the usage statistics that you are used to seeing but the data may be anonymized.

Following our SDK release schedule we have released TestFlight SDK 1.0 BETA 1. As mentioned this new version of the SDK no longer accesses the device unique identifier and as such is App Store safe. Following our SDK release schedule we forsee that this version will be bumped up to full release status no later than March 30, 2012. When SDK 1.0 BETA becomes the official release we will begin deprecating all previous SDK releases.

As of May 31, 2012 we will no longer accept uploaded builds that contain an SDK version lower than 1.0. We will continue to accept data from previous versions of the SDK indefinitely.

Today TestFlight moves to its new home. The new home is a bare metal infrastructure which brings you a faster more scalable TestFlight. In a follow up post we will discuss some of the technical pieces and the decisions made, for now we just wanted to tell you guys that we are moving, and why.

Ghost Hunting

Cloud hosting has some fantastic benefits, we were specifically attached to the cost and the speed at which we could bring up new instances. What we were not attached to was the inconsistent performance and lack of predictability.

Tracking down bottlenecks in the infrastructure felt like hunting ghosts. There were times were the system locked up hard and the only explanation we walked away with was resource contention. We already consumed the majority of the shared resources available so there was nowhere to go but down.

Hello Anchor

While trying to figure out an ideal load balancing situation for TestFlight I stumbled on this article http://www.anchor.com.au/blog/2009/10/load-balancing-at-github-why-ldirectord/.  Turns out the Anchor team helped scale GitHub. After a few conversations with Anchor, it was clear their team was phenomenal fit for TestFlight.

We would love to take credit for everything involved with this migration but the reality is that Anchor brought a wealth of experience to the table. They took our stack, analyzed it and came up with a plan of attack which involved some fantastic technologies only well-bearded individuals should touch.

The New Infrastructure

Once things have settled down we will post a follow up with some more technical details. This new infrastructure will not only help us scale as we grow, but it should provide immediate performance improvements. We hope that everyone is as excited as we are.

The TestFlight crew is growing! If you are interested in working with us, please apply!

A Real-time Dashboard for Actions and Revenue

B + TF = TF Live

We are excited to announce that TestFlight was acquired by Burstly, and we are jointly launching TestFlight Live today! TestFlight Live is a real-time dashboard that highlights actions and revenue for iOS apps. The TestFlight Live feature set is broken down into four segments: engagement, audience, revenue, and stability. The goal of the product is to provide a real-time display of the important factors happening in your app right now. It is available via Safari and Chrome on the desktop, and on the go on your iPad and iPhone.

For those of you unfamiliar with Burstly, they are a team that shares our vision of improving the ecosystem for developers. Burstly has been working to help some of the biggest apps in the industry including Words with Friends, Angry Birds, PaperToss, and Tetris. They know how to support partners at scale. They are also good friends who we are excited to work closer with. We are thrilled to be joining forces with their team, and feel this is the best place for us to continue building the tools that developers love.

TestFlight has experienced phenomenal growth since we launched last year.  We now have over 70,000 developers sharing more than 130,000 apps with a group of 280,000 testers! While the widespread adoption of our product has been humbling, we know we need to continue investing in features and performance to meet the needs of our expanding client base. This is where the investment dollars and scaling guidance from Burstly will be invaluable. With performance and support issues, and tremendous customer feedback, we are aware of what we need to improve upon. We are committed to tackling these issues to enhance the TestFlight experience and the additional resources provided by this acquisition are vital to that effort’s success.  We are about to roll out major updates with the help of some new resources provided by Burstly in addition to the great work by our team.

Coming to TestFlight in March:

  • Better performance - we are putting the finishing touches on an infrastructure overhaul that includes moving to managed dedicated hosting led by Anchor Systems (http://www.anchor.com.au/blog/2009/09/github-designing-success/)
  • New UI for both desktop and mobile - completely revamped with improved workflows and more flexibility so we can continue to expand the product
  • Desktop app + expanded API - screaming fast uploads, local IPA validations, and the most important bits of TestFlight on your desktop. The side effect of a rich desktop app is a rich API. We are excited to see what you will create with an expanded API
  • Faster customer response times and an improved knowledgebase – we have grown our support team to make the TestFlight experience more enjoyable
  • We’re hiring! If you’re excited to create amazing products that solve problems in all of the areas of the mobile app lifecycle, please let us know

TestFlight and Burstly will continue to be independent products. TestFlight remains a free service and optional paid features will be introduced in the future. TestFlight will continue to build the best developer tools and will include Burstly features only to improve product functionality (as in the case of adding revenue to TestFlight Live), and vice versa for Burstly products.

If you are not completely familiar with Burstly’s business, you are not alone since we did not fully grasp it when we first met back in April, 2009. Burstly offers developer’s tools to help better monetize their apps. The toolset allows mobile developers to run any type of content or messaging to its users, track in-app purchases from buttons or banners, cross-promote other apps, and to work with a wide variety of 3rd party ad partners to improve revenue.  Burstly’s mission is to empower developers by providing data and visibility into their business, along with a toolset to act on that data. This is very similar to how our mission at TestFlight. We provide developers with the tools they need to be in control of their beta testing experience. With the launch of TestFlight Live we are starting to help with their business after their app has launched as well. 

Mobile App Lifecycle

Both companies solve complex problems within the app lifecycle. TestFlight handles the beginning with beta testing tools, while Burstly manages the final stages with monetization options. Together, we are working to solve everything in between. A good first step in this direction is TestFlight Live. 

TestFlight Live

We have been planning on launching a production version of TestFlight for some time, but we wanted to push ourselves to start solving production problems and not simply copy the beta feature set. Along with help from the Burstly team, we think we have taken a great first step with TestFlight Live. Our goal with TestFlight Live is to provide a real-time dashboard that displays real-time usage statistics, actions, symbolicated crash reports, and revenue. For the first time, developers will have a single dashboard that provides enough information to derive insights into Revenue Per User (RPU) and Customer Lifetime Value (CLV) to better understand your app business. Previously, this level of information would be from multiple sources and there was no easy way to collect it.

Burstly was the key contributor to the revenue portion of TestFlight Live, as they developed the APIs that make it possible. The revenue source options in TestFlight Live enable developers to include app sales data, in-app purchase data, and ad network revenue from multiple partners. You do not need to work with Burstly to pull in any of this data. If you do not want the revenue segment in your dashboard, we have provided a way for you to hide it.

Learn more about the features of TestFlight Live.

History

Almost three years ago, it took a well-connected Portland iPhone maven, Raven Zachary, to introduce two mobile guys who could not find each other in LA. Thank you @ravenme! Through this introduction we became one of Burstly’s first customers when we agreed to be their guinea pig with our app, Gigotron. They even put us in their launch video as their first customer (jump to 1:40). We were actually debating building something similar at the time to enable local bands to promote their shows, but it was clear Burstly’s toolset and thinking was a few steps ahead of ours when it came to promotion/monetization. Ever since then, our teams have been working together.

We are looking forward to waking up everyday to work with our friends and build better products than we are able to build alone.

Privacy

While we are thrilled to join forces with Burstly, we won’t be surprised if not all of our customers are equally enthusiastic. After internal discussions, we felt like the two biggest reasons for a negative reaction would be: (1) TestFlight would change for the worse and (2) privacy concerns and trust with your data. Since we hope it is already clear by this point that TestFlight is only getting better, we want to address the trust issue.  TestFlight handles top secret developer projects, Burstly handles top secret financial data for some of the largest apps in the world. Both companies are responsible for safeguarding their customers’ precious data  and can be successful only by maintaining the highest standards in this regard.

We are committed to improving and growing the TestFlight experience. If anything about our new partnership with Burstly causes you concern we hope you will visit TestFlight Live and see this effort as a first step towards building better tools for all developers.

We have strong convictions in our future roadmap and the benefits to our community of trusted TestFlight developers. We hope you will give us enough time to execute so the products and our actions speak louder than anything we could possibly write in this post. If, for any reason, you don’t want to continue using our toolset due to our new relationship you can use the “remove account” button under “account settings” and erase all of your data and delete your account.

Ready to get started with TestFlight Live? Simply insert one line of code into your production app or leave the SDK you have been using for beta testing. We could not be any more excited about the opportunity to solve developer’s problems and help drive the app ecosystem forward.

TestFlight SDK 0.8 is live!

The TestFlight team has been hard at work trying to bring you an updated SDK. We’re happy to say it’s arrived! Here are a few of the highlights.

Signal Safe Crash Reporting

The main focus of the 0.8 update to the SDK was our crash reporting mechanisms. Our uncaught exception and signal handling has gone through extensive improvements since the 0.7 release. Part of this effort was removing any Objective-C and non-signal safe code from the crash reporting functionality of our SDK. Our users have also helped us identify that we were missing the SIGTRAP signal in our signal handler which has been added. The other changes involve using a signal safe implementation of MessagePack that allows us to save all of your data safely to files as we gather the crash report. This means that if, for any reason during the signal or exception, there is an interruption the data that we have gathered thus far is safe and will be transmitted on the next launch of the application.

Realtime Crash Reports

We feel that having crash reports being reported as they occur is extremely important. In order to maintain this it requires that we run some potentially less signal safe code in our crash reporting mechanisms. Initially we were using the same asynchronous networking code that we use in the main part of the library. This is Objective-C based and we feel that it is an extremely effective networking solution and we will continue to use it in the main portion of our SDK. However, it has the potential to allow the rest of the application to continue running during a signal which could lead to corruption of data. We now use an entirely C-based approach to networking while sending crash reports. If, for any reason, we are unable to send the report we will send it the next time that the application is launched with an active connection to the network.

Stack Trace Improvements

In some circumstances we noticed that the stack trace for exceptions was incorrect. This was caused by obtaining the stack trace from inside the NSUncaughtExceptionHandler. This method, which used to work correctly, no longer works as of iOS 5. We now use the call stack provided by NSException which, during our testing, accurately reports the call stack from iOS 3 to iOS 5.

iOS 3 Support

One issue a few people have pointed out was that we did not handle iOS 3 very well. We are happy to say that we have resolved any issues with and now support our full feature set with iOS 3. While this does not affect all of our users, it is important to us to provide you with the tools to fully test your products across all devices and OS versions.

Remote NSLogs

We have tried hard to maintain our current feature set while implementing our improved crash reporting, but there were a couple of features that did not make the cut for version 0.8. The first of which is capturing NSLogs during a crash. We currently get your NSLogs from the Apple System Log, which is very slow and not signal safe. We are aware that capturing NSLogs are especially important during a crash and we will be bringing back a way to obtain the log during a crash. The other feature we have removed during this process is crash logs from the iOS Simulator. We feel that, while the Simulator is a useful tool, it is used with Xcode most of the time and it is less useful to record the exceptions from the Simulator inside of TestFlight.

Future Improvements:

  • A new logging system. We no longer feel that NSLogs are the best way to record logging information going forward. They have been useful in showing us that our users really like the ability to have their logging statements sent to them remotely. We are working to provide a way to do this without any negative impact to your application.
  • Low memory exit recording. We currently do not report anything when a low memory exit occurs. This type of exit is just as important to our users as crash reporting and we will be addressing this in upcoming versions.

You can grab the updated TestFlight SDK at https://testflightapp.com/sdk/

This post is a bit long, so here’s a brief overview:

We wrote a portable version of Apple’s closed source atos command line tool to power TestFlight’s new real time symoblication of crash reports. We are considering open sourcing this tool for the iOS community to leverage as a whole if there’s interest.

To use this new feature, upload a .dSYM via the crashes page; your crashes will be symbolicated as they occur and you can start solving issues even faster.

If you’re interested in the technical details, read on!

The SDK

If you’ve integrated the TestFlight SDK into any of your applications you may have noticed that we recently released symbolication for crash reports. You can now upload a .dSYM via the crashes page (or the upload API) and crashes you receive will be symbolicated on the fly.

Our mission at TestFlight is to help developers create the highest quality apps possible. We believe that real time tools improve the feedback loop by shortening the testing cycle and enable developers to spend more time building higher quality apps.

We’ve been hard at work on all of our SDK features, and we thought we’d share our experience regarding how we tackled symbolication. For information about the SDK, visit the SDK page at https://testflightapp.com/sdk/.

What is symbolication, and why should I care?

Symbolication is the process of translating addresses in crash reports to function names, method names, file names and line numbers. Raw crash reports received from users via email or downloaded from iTunes Connect look somethings like this:

8   libobjc.A.dylib                     0x33d6cc8b 0x33d68000 + 19595
9   CoreFoundation                      0x33893465 0x3388b000 + 33893
10  HelloTestFlight                     0x0002d109 0x2b000 + 8457
11  HelloTestFlight                     0x0002d0df 0x2b000 + 8415
12  CoreFoundation                      0x33899571 0x3388b000 + 58737
13  UIKit                               0x333ceec9 0x333b2000 + 118473

0x2b000 - 0x3d000  HelloTestFlight armv7 <a9603692b66f3a72847c380a50ce2347>

After symbolication this same crash report looks something like this:

8   libobjc.A.dylib                     0x33d6cc8b objc_exception_throw + 71
9   CoreFoundation                      0x33893465 -[__NSArrayI objectAtIndex:] + 161
10  HelloTestFlight                     0x0002d109 -[HTFViewController indexOutOfBounds] (HTFViewController.m:52)
11  HelloTestFlight                     0x0002d0df -[HTFViewController doIndexOutOfBounds] (HTFViewController.m:56)
12  CoreFoundation                      0x33899571 -[NSObject(NSObject) performSelector:withObject:withObject:] + 25
13  UIKit                               0x333ceec9 -[UIApplication sendAction:to:from:forEvent:] + 85

0x2b000 - 0x3d000  HelloTestFlight armv7 <a9603692b66f3a72847c380a50ce2347>

Specifically, symbolication has converted addresses and offsets like 0x2b000 + 8457 into symbols, file names and line numbers like -[HTFViewController indexOutOfBounds] (HTFViewController.m:52). In addition to the method, the file name and line number where the crash occurred are pinpointed:

    HTFViewController.m:

    50  - (void)indexOutOfBounds {
    51      NSArray *array = [NSArray arrayWithObject:@"HelloTestFlight"];
->  52      [array objectAtIndex:2];
    53  }

This information is similar to the feedback Xcode provides when a crash occurs in development, and it is invaluable for tracking down crashes in the field.

Symbolicating a raw crash report

A hard requirement for symbolication is that a “DWARF with dSYM” was generated when your app was built. If you use the “Archive” option in Xcode 4, a .dSYM containing a DWARF (Debugging with Attributed Record Formats) file is automatically generated and saved in the archive for you.

Given a raw crash report it’s actually fairly simple to symbolicate it:

  1. Launch Xcode
  2. Open the Organizer (⌘⇧2)
  3. Select the devices tab and drop the crash report on “Device Logs”

After a few moments a fully symbolicated version of the crash will appear. The tool that Apple uses to symbolicate behind the scenes is a perl script named symbolicatecrash. Given that Xcode is installed, you can find symbolicatecrash on your machine as follows:

$ find /Developer -name symbolicatecrash

With a crash report named testflight.crash in hand, instead of using Xcode you can symbolicate the crash via the command line:

$ $(find /Developer -name symbolicatecrash) testflight.crash

symbolicatecrash does quite a few things to make the process of symbolication simple. Notably, the tool figures out where to look for debugging information. You may have noticed the following line in the crash reports above:

0x2b000 - 0x3d000  HelloTestFlight armv7 <a9603692b66f3a72847c380a50ce2347>

This line tells us that the HelloTestFlight binary was loaded in memory at address 0x2b000 on an armv7 device when the crash occured. Additionally the UUID (universally unique identifier) of the specific binary that was loaded is a9603692b66f3a72847c380a50ce2347. The format for binaries on Darwin (the open source core of Mac OS X and iOS) is called Mach-O, and Apple engineers made the fabulous decision to tag every Mach-O binary with a UUID for easy identification.

symbolicatecrash uses the binary UUID to find the corresponding .dSYM and .app bundles via spotlight (i.e. the mdfind command line utility). The DWARF within the .dSYM is tagged with the same UUID as the binary, which is what makes this search possible. In addition to the DWARF, symbolicatecrash locates debugging symbols for libraries in the crash report by scanning various standard locations on the file system and inspecting candidate binaries. These tasks are accomplished by involking several command line utilities:

  • mdfind and mdls, a.k.a Spotlight
  • otool - object file displaying tool
  • size - print the size of the sections in an object file
  • lipo - create or operate on universal files

Finally, symbolication of addresses is performed by:

  • atos - convert numeric addresses to symbols of binary images or processes

The point is that symbolicatecrash spawns numerous subprocesses to symbolicate a crash report, the primary being atos. This method works well for symbolicating crash reports one at a time, but symbolicatecrash is not suited for batch symbolication. In fact, symbolicatecrash takes about 2 seconds per crash report:

$ time for i in {1..10}; symbolicatecrash testflight.crash > /dev/null; done

real    0m19.394s
user    0m7.553s
sys     0m9.175s

The challenges of batch symbolication

There are a couple challenges that make real time symbolication as a service difficult. Although 2 seconds per crash report may not seem like a long time, when there are thousands of crash reports pouring in every fraction of a second matters.

The first challenge is speeding up symbolicatecrash, and we were actually able to offload most of this work altogether.

The second challenge is based in the fact that symbolicatecrash relies on Mac OS X/Darwin specific tools. While some of the tools are open source (http://opensource.apple.com/source/cctools/cctools-806/) and portable versions do exist (http://code.google.com/p/iphone-dev/), the key tool, atos, is closed source. We did some research and it turns out that with a little work it’s possible to use gdb to convert addresses to symbols, but alas, Apple’s version of gdb isn’t portable.

Here’s what we did to overcome these obstacles.

Speeding up symbolicatecrash

Speeding up symbolicatecrash is really a matter of being smarter about symbolicating library symbols. Scanning standard locations and spawning subprocesses to inspect libraries is very slow. Since developers associate .dSYMs with builds, there is no need to use Spotlight or otherwise search for debugging symbols. To speed things up we first created an index of library binaries based on UUID (and rewrote symbolicatecrash accordingly). That sped up symbolication about 8x.

This isn’t the approach we deployed, however. It turns out that libraries on iOS include debug symbols on each device, so what we actually do is symbolicate libraries client-side before sending crash reports to the TestFlight servers. This process of symbolication is different from the one described above since we aren’t dealing with DWARFs and there’s no file name and line number information to surface.

Writing a portable atos

Running a cluster of Mac OS X machines seems like the obvious, quick solution for providing symbolication as a service. There a few drawbacks to this approach, however:

  • We would have to ship data back a forth to a remote cluster
  • Maintaining a remote cluster is somewhat complex and operationally time consuming
  • A Mac OS X cluster can be expensive to operate

After some research we determined that re-writing atos would involve:

  1. Parsing universal files
  2. Parsing Mach-O binaries
  3. Parsing DWARF
  4. Deriving line and file information from DWARF “statement programs”

The file formats and derivation process are well documented, so we were convinced that we could write the tool. This is a better investment than maintaining a cluster, in our opinion. That, and we figured it would be a fun challenge.

I won’t go into too many details, but here’s what atos basically does:

Given the stack frame:

10  HelloTestFlight                     0x0002d109 0x2b000 + 8457
    ^                                   ^          ^
    Binary image name                   runtime    load
                                        address    address
  1. Determine the relative address of the symbol:

    runtime address     = 0x0002d109
    load address        = 0x2b000
    relative address    = runtime address - load address    = 0x2109
    
  2. Determine the vm address the binary was built at by looking at the __TEXT Mach-O load command:

    vmaddr              = 0x1000
    address             = vmaddr + relative address         = 0x3109
    
  3. Load the DWARF data from the DWARF-related Mach-O sections

  4. Find a DWARF compilation unit containing a subprogram with the given address; the subprogram name is the symbol

  5. Derive the line information for the address using the compilation unit’s statement program

If you’re interesting in learning more about Mach-O and DWARF, here are the definitive resources:

http://developer.apple.com/library/mac/#documentation/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html http://dwarfstd.org/doc/dwarf-2.0.0.pdf

The Result

The resulting version of symbolicatecrash is a simple wrapper around atos that parses crash reports and offloads the rest to atos. Here is how it performs:

$ time for i in {1..10}; symbolicatecrash testflight.crash > /dev/null; done

real    0m0.997s
user    0m0.685s
sys     0m0.267s

…on linux, which means we can symbolicate crashes locally.

We’re pretty excited about these results. This is almost a 20x performance increase over the version of symbolicatecrash provided with Xcode. Not only can we now provide real time symbolication for developers, but we succeeded in keeping our infrastructure simple which allows us to focus on creating even more tools.

For the iOS community

We are considering open sourcing our portable version of atos. If you are a member of the iOS community and feel that you would benefit from having this tool available, let us know!

For now, check out the TestFlight SDK at https://testflightapp.com/sdk/. It will give you access to real time crash reporting and symbolication as well as other powerful tools such as:

  • Remote NSLogging
  • Real time session data
  • In-app questions
  • and In-app updates

Here’s to productive testing!