{"id":19607056,"url":"https://github.com/bookingcom/perfsuite-ios","last_synced_at":"2026-01-27T16:10:31.130Z","repository":{"id":173673819,"uuid":"651107585","full_name":"bookingcom/perfsuite-ios","owner":"bookingcom","description":"PerformanceSuite: A Swift-based iOS library for monitoring app performance and quality metrics.","archived":false,"fork":false,"pushed_at":"2025-10-06T17:26:57.000Z","size":19394,"stargazers_count":129,"open_issues_count":1,"forks_count":11,"subscribers_count":8,"default_branch":"main","last_synced_at":"2025-11-14T02:19:52.299Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bookingcom.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2023-06-08T14:05:34.000Z","updated_at":"2025-10-27T12:21:23.000Z","dependencies_parsed_at":"2023-06-28T12:00:21.450Z","dependency_job_id":"ab50bf36-fb6e-4f63-905a-67ac806fcad9","html_url":"https://github.com/bookingcom/perfsuite-ios","commit_stats":null,"previous_names":["bookingcom/perfsuite-ios"],"tags_count":29,"template":false,"template_full_name":null,"purl":"pkg:github/bookingcom/perfsuite-ios","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bookingcom%2Fperfsuite-ios","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bookingcom%2Fperfsuite-ios/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bookingcom%2Fperfsuite-ios/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bookingcom%2Fperfsuite-ios/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bookingcom","download_url":"https://codeload.github.com/bookingcom/perfsuite-ios/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bookingcom%2Fperfsuite-ios/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28816557,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-27T12:25:15.069Z","status":"ssl_error","status_checked_at":"2026-01-27T12:25:05.297Z","response_time":168,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-11T10:08:35.290Z","updated_at":"2026-01-27T16:10:31.111Z","avatar_url":"https://github.com/bookingcom.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":" ![Tests](https://github.com/bookingcom/perfsuite-ios/actions/workflows/tests.yml/badge.svg)\n ![CodeQL](https://github.com/bookingcom/perfsuite-ios/actions/workflows/codeql.yml/badge.svg)\n ![Cocoapods](https://img.shields.io/cocoapods/l/PerformanceSuite)\n ![Cocoapods](https://img.shields.io/cocoapods/v/PerformanceSuite)\n ![Cocoapods platforms](https://img.shields.io/cocoapods/p/PerformanceSuite)\n ![Code Coverage](https://raw.githubusercontent.com/bookingcom/perfsuite-ios/badges/.badges/main/code_coverage.svg)\n\n![PerformanceSuite_logo_small](https://github.com/bookingcom/perfsuite-ios/assets/983021/384c8786-c7ee-40cf-a46a-ee7ee656e814)\n\n\n# PerformanceSuite\n\nPerformanceSuite is an iOS Swift library designed to measure and collect performance and quality metrics of iOS applications. \n\nCompared to other solutions like MetricKit, Firebase Performance, Instabug, Sentry, etc., it offers additional flexibility. However, it focuses on the native part of performance monitoring. For storing and visualizing your metrics, building monitoring graphs, and setting up alerts, you will need to have your own backend.\n\nThis library is used in the [main Booking.com iOS app](https://apps.apple.com/app/booking-com-hotels-travel/id367003839) which is used by millions of users every day. We've described how we measure performance at Booking.com in [this article](https://medium.com/booking-com-development/measuring-mobile-apps-performance-in-production-726e7e84072f).\n\nWe've also opened the code for the similar [Android PerformanceSuite](https://github.com/bookingcom/perfsuite-android).\n\n## Pros\n\n- Performance events are delivered in real-time directly to your code, allowing for comprehensive analysis.\n- You can monitor performance within your A/B tests.\n- You have the flexibility to build any real-time performance charts with custom alerting.\n\n\n## Cons\n\n- A custom backend is needed to collect the metrics, display the graphs and setup alerting. \n\n## Supported features\n\n- [TTI](https://github.com/bookingcom/perfsuite-ios/wiki/TTI) (Time to Interactive) monitoring for screens.\n- [Freeze time](https://github.com/bookingcom/perfsuite-ios/wiki/Freeze-Time) rendering performance monitoring for screens.\n- Overall app freeze time monitoring.\n- [Startup time](https://github.com/bookingcom/perfsuite-ios/wiki/Startup-Time) monitoring.\n- Fatal and non-fatal [hangs](https://github.com/bookingcom/perfsuite-ios/wiki/Hangs) with the stack trace.\n- Watchdog [terminations](https://github.com/bookingcom/perfsuite-ios/wiki/Watchdog-Terminations) (memory or CPU terminations).\n- Logging of all UIKit controller events for easier debugging.\n\n#### Check our [Wiki](https://github.com/bookingcom/perfsuite-ios/wiki) for more details.\n\nPlease note that PerformanceSuite currently does not support the tracking of standard crashes. You will need an additional tool to collect stack traces for crashes (for example, Firebase Crashlytics).\n\n## How it works\n\n`PerformanceSuite` monitoring should be activated as your application launches, by supplying an object that is set up to process the performance metrics. As your application continues to run, you'll receive callbacks that deliver these metrics.\n\n```swift\n\nfunc startupTimeReceived(_ data: StartupTimeData) { ... }\n\nfunc fatalHangReceived(info: HangInfo) { ... }\n\nfunc nonFatalHangReceived(info: HangInfo) { ... }\n\nfunc viewControllerLeakReceived(viewController: UIViewController) { ... }\n\nfunc watchdogTerminationReceived(_ data: WatchdogTerminationData) { ... }\n\nfunc appRenderingMetricsReceived(metrics: RenderingMetrics) { ... }\n\n```\n\nFor screen-level metrics you should return `ScreenIdentifier` from `screenIdentifier(for:)` or nil if this view controller shouldn't be tracked. Check [Screen identifiers] for the example.\n\n```swift\n\nfunc screenIdentifier(for viewController: UIViewController) -\u003e ScreenIdentifier? { ... }\n\nfunc ttiMetricsReceived(metrics: TTIMetrics, screen: ScreenIdentifier) { ... }\n\nfunc renderingMetricsReceived(metrics: RenderingMetrics, screen: ScreenIdentifier) { ... }\n\n```\n\n\n## SwiftUI support\n\nPerformanceSuite screen tracking heavily relies on the UIKit UIViewController's lifecycle.\n\nFor purely SwiftUI apps, iOS still creates `UINavigationController` under the hood to perform navigations, and these cases are supported by PerformanceSuite.\n\nHowever, custom SwiftUI transitions that do not create any `UIHostingController` under the hood are not currently automated. For now you can use [Fragment TTI tracking](https://github.com/bookingcom/perfsuite-ios/wiki/TTI#fragments-tti-tracking) for such cases. We may introduce some syntax sugar later if there is a demand for that.\n\nFor most apps, though, the current setup is good enough to automatically track screen openings with SwiftUI views inside `UIHostingController`. Check [Usage](README.md#usage) section for the details.\n\n## Installation\n\n#### Swift Package Manager\n- In Xcode, select File \u003e Add Packages.\n- Enter https://github.com/bookingcom/perfsuite-ios in the \"Search or Enter Package URL\" dialog.\n- In the next page select \"Up to Next Major\" and specify the latest version.\n- On the final page, choose the `PerformanceSuite` library and add it to your target.\n- Your package dependency will be added to your .xcodeproj file.\n\n#### CocoaPods\nTo integrate `PerformanceSuite` into your Xcode project using CocoaPods, specify it in your Podfile:\n\n```\npod 'PerformanceSuite'\n```\n\nCurrently CocoaPods repo [has problems](https://github.com/CocoaPods/cocoapods.org/issues/424) with indexing the new added pods, that's why if it doesn't work you may specify the source url and tag\n\n```\npod 'PerformanceSuite', :git =\u003e 'https://github.com/bookingcom/perfsuite-ios.git', :tag =\u003e '0.0.4' # use the last released version here\n```\n\n## Usage\n\nTo receive performance events, you must have a class implementing some of the following protocols:\n- `TTIMetricsReceiver`\n- `RenderingMetricsReceiver` \n- `AppRenderingMetricsReceiver`\n- `WatchDogTerminationsReceiver`\n- `HangsReceiver`\n- `ViewControllerLeaksReceiver` \n- `StartupTimeReceiver`\n- `ViewControllerLoggingReceiver`\n- `FragmentTTIMetricsReceiver`\n\nAlternatively, you can use the `PerformanceSuiteMetricsReceiver` to receive all events.\n\nPerformance monitoring should be initiated as early as possible in your app. For instance, you could begin at the start of the `application(application:didFinishLaunchingWithOptions:)` method.\n\n```swift\nlet metricsConsumer = MetricsConsumer()\ntry PerformanceMonitoring.enable(config: .all(receiver: metricsConsumer))\n\n// or with more flexibility\n\nlet metricsConsumer = MetricsConsumer()\nlet config: Config = [\n    .screenLevelTTI(metricsConsumer),\n    .screenLevelRendering(metricsConsumer),\n    .appLevelRendering(metricsConsumer),\n    .hangs(metricsConsumer),\n]\ntry PerformanceMonitoring.enable(\n    config: config,\n    // you may pass your own key-value storage\n    storage: KeyValueStorage.default,\n    // you may pass a flag if app did crash from Crashlytics\n    didCrashPreviously: didCrashPreviously\n)\n\n```\n\n### Screen identifiers\n\nAll screen-level metrics are coming from PerformanceSuite to your code with the `UIViewController` object. To convert view controller object to a `ScreenIdentifier` you may use such approach:\n\n- Define `PerformanceScreen` enum with screen identifiers for all your screens\n- Define protocol `PerformanceTrackableScreen` where every screen should return this enum\n- Add SwiftUI support for `UIHostingController` if needed\n\n```swift\n\n// We define enum with all our possible screens\n// If you have too many screens, there can be several enums, \n// or just a string identifier.\nenum PerformanceScreen: String {\n    case search\n    case details\n    case checkout\n}\n\n// We define a protocol for screens to conform\nprotocol PerformanceTrackableScreen {\n    var performanceScreen: PerformanceScreen? { get }\n}\n\n// For view controllers it is easy, we just return which screen is this\nextension SearchViewController: PerformanceTrackableScreen {\n    var performanceScreen: PerformanceScreen? { .search  }\n}\n\n// If you have SwiftUI screens without corresponding custom `UIHostingController`, \n// you will need to add introspection logic to find root views \n// in any `UIHostingController` in the app.\n//\n// We should conform to this protocol in the topmost view of the screen.\n//\n// NB: if possible, better to use your own subclass for `UIHostingController`\n// and implement `PerformanceTrackableScreen` only in your subclass.\n// Otherwise it may be additional performance overhead to introspect \n// all hosting controllers in the app\nextension CheckoutScreenSwiftUIView: PerformanceTrackableScreen {\n    var performanceScreen: PerformanceScreen? { .checkout }\n}\n\n// We also need to implement the protocol in UIHostingController,\n// So we can determine which is the SwiftUI view inside this controller.\nextension UIHostingController: PerformanceTrackableScreen {\n    var performanceScreen: PerformanceScreen? {\n        return (introspectRootView() as? PerformanceTrackableScreen)?.performanceScreen\n    }\n}\n\n// In our metrics consumer we will receive UIViewController \n// and should determine which screen is this.\nclass MetricsConsumer: TTIMetricsReceiver {\n    func screenIdentifier(for viewController: UIViewController) -\u003e PerformanceScreen? {\n        (viewController as? PerformanceTrackableScreen)?.performanceScreen\n    }\n\n    func ttiMetricsReceived(metrics: TTIMetrics, screen: PerformanceScreen) {\n        // send the event to your backend with this identifier\n        send(metric: \"tti\", value: metrics.tti.seconds, screen: performanceScreen.rawValue)\n    }\n}\n\n```\n\n## How to reproduce metrics?\n\nIn the repository we have the sample app `PerformanceApp`, on the first screen there are options to generate all the possible metrics:\n\n\u003cimg width=\"513\" alt=\"menu\" src=\"https://github.com/bookingcom/perfsuite-ios/assets/983021/268375e2-5b2d-433b-9741-dad5091f9698\"\u003e\n\n- Startup time is generated on a `PerformanceApp` launch\n- Freeze time and App Freeze time will be generated after you open *Freeze time* screen\n- For other metrics select corresponding menu option\n\nWe use this `PerformanceApp` in the integration UI tests, to verify all the metrics are properly generated.\n\n## Development\n\nTo launch project locally:\n- install CocoaPods with `gem install cocoapods`\n- generate `Pods` folder with `pod install`\n- open `Project.xcworkspace` to launch sample `PerformanceApp` or run tests\n- Use `PerformanceApp` scheme to launch the app\n- Use `UnitTests` to launch unit tests\n- Use `UITests` to launch integration UI tests. Note, that this scheme is compiling in Release mode.\n\n# ACKNOWLEDGMENT\nThis software was originally developed at Booking.com. With approval from Booking.com, this software was released as open source, for which the authors would like to express their gratitude.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbookingcom%2Fperfsuite-ios","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbookingcom%2Fperfsuite-ios","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbookingcom%2Fperfsuite-ios/lists"}