Since Firebase first released an iOS SDK, CocoaPods has been the preferred way to add Firebase to your iOS projects. CocoaPods has served the iOS community well and has made adding libraries and frameworks as easy as adding their package name to your project's Podfile file and running pod install.
Podfile
pod install
In recent years, Swift Package Manager has grown in popularity thanks to being officially supported by Apple, and its tight integration with Xcode. The 2020 iOS Developer Community Survey shows that more than 41% of app developers use Swift Package Manager in their business apps. For hobby/personal apps, that number is even higher at > 56% of developers using Swift Package Manager in their projects.
Adding support for Swift Package Manager has been one of the most requested features in our issue tracker:
Firebase shipped initial (beta) support for Swift Package Manager in August 2020 with Firebase 6.31.0 for a partial set of Firebase products.
Today, we are excited to announce that as of Firebase 8.6.0 for iOS, Firebase fully supports Swift Package Manager. This means you can now add Firebase to your iOS project without leaving Xcode. Gone are the days of having to maintain a working Ruby installation, or having to remember the correct command line arguments just to be able to add a Swift library to your iOS project.
Adding Firebase to your iOS project is easier than ever before with Xcode 12.5:
Adding support for Swift Package Manager was a multi-year project that not only required us to refactor our directory structure and build options to conform to SwiftPM's requirements - we also worked closely with the SwiftPM community to resolve integration issues with binary libraries, resource support, and - last but not least - unit testing support.
Performance Monitoring was the last Firebase product that was missing support for Swift Package Manager, and just a few days ago, the Performance Monitoring team completed their work to get ready for SwiftPM. This involved substantial investment in migrating from Protobuf to nanopb, a refactoring that reduced the size of the SDK by more than 30%.
We know that many of you have been looking forward to being able to migrate to a SwiftPM-only project setup, and we're excited to be able to say that using Swift Package Manager is now the preferred way to add Firebase to your iOS project.
We're working on updating the documentation, setup flows, and quickstart apps to reflect this change.
Come visit us on our GitHub discussion board and issue tracker, and let us know what you think, or if you have any questions about migrating from CocoaPods to Swift Package Manager.
You've asked for it, and now it's here! We're excited to announce that version 9 of the Firebase SDK is now generally available. This new version adopts a module first format that is optimized for elimination of unused code. The result is a potential significant reduction of Firebase library code in JavaScript bundles, up to 80% in some scenarios.
As of today running npm install firebase will download the version 9 library. This new API is a major release and introduces several breaking changes. Upgrading to the new version can be done all at once or at your own pace with our compatibility library (more on that below). This post covers everything you need to know to get started. Check out our upgrade guide as well as our guide to using the new SDK with module bundlers for detailed guidance.
npm install firebase
API changes for reduced size
Version 9 introduces a functional approach. In previous versions the API was organized into a traditional object-oriented structure. Using individual functions instead of structured objects allows JavaScript module bundlers such as webpack and Rollup to remove any unused code from the library. This is a concept known as tree shaking.
import { initializeApp } from 'firebase/app'; import { getAuth, onAuthStateChanged, getRedirectResult } from 'firebase/auth'; const firebaseApp = initializeApp({ /* config */ }); const auth = getAuth(); onAuthStateChanged(auth, user => { console.log(user); });
While this library organization is new, we have kept in place many familiar API concepts.
// 9.0.0 import { initializeApp } from 'firebase/app'; import { getAuth, onAuthStateChanged } from 'firebase/auth'; const firebaseApp = initializeApp({ /* config */ }); const auth = getAuth(); onAuthStateChanged(auth, user => { console.log(user); }); // 8.8.1 import firebase from 'firebase/app'; import 'firebase/auth'; const firebaseApp = firebase.initializeApp({ /* config */ }); const auth = firebaseApp.auth(); auth.onAuthStateChanged(user => { console.log(user); });
The sample above compares the same functionality, has the same amount of lines of code, and a similar API. The version 9 code however is 72% smaller than the version 8 example.
Keep in mind that while our functional approach is beneficial for tree shaking, this does not require you to write your code functionally. This new format provides an "import only what you need" approach. You can still structure your code in the ways that work best for you and your team.
import { getApp } from 'firebase/app'; import { getAuth, onAuthStateChanged } from 'firebase/auth'; class AuthService { constructor(firebaseApp) { this.auth = getAuth(firebaseApp); } waitForUser(callback) { onAuthStateChanged(this.auth, user => { if(user != null) { callback(user) } }); } } const authService = new AuthService(getApp()) authService.waitForUser(user => { });
import { getApp } from 'firebase/app'; import { getAuth, onAuthStateChanged } from 'firebase/auth'; function waitForUser(auth, callback) { onAuthStateChanged(auth, user => { if(user != null) { callback(user) } }); } const auth = getAuth(getApp()); waitForUser(auth, user => { });
The samples above follow different structures. However, they have nearly the same bundle size. This is because they import the same pieces of functionality from the Firebase SDK.
A compatibility library for an easier upgrade
We understand that having to update code can be a lot of work. While your end users will experience real benefits in terms of bundle size and therefore page load performance, we want to make sure you can upgrade with minimal friction.
To simplify the upgrade process we have provided a compatibility library that ships with the version 9 npm package and is also available via a CDN script. To use the compatibility library via npm, you only need to update the import path.
import { initializeApp } from 'firebase/compat/app'; import 'firebase/compat/auth; import { onAuthStateChanged } from 'firebase/auth'; const firebaseApp = firebase.initializeApp({ /* config */ }); const auth = firebaseApp.auth(); onAuthStateChanged(auth, user => { console.log(user); });
This library mirrors the version 8 API while using the version 9 library under-the-hood. It does not work with tree shaking, but it allows you to use the old and new APIs together. We refer to this as interop-mode.
Once your code is fully upgraded, you can remove the compatibility library and begin to see any potential tree shaking benefits.
Introducing Firestore Lite
We're also excited to announce our newest library, Firestore Lite. Firestore Lite provides a REST based API for Firestore at a fraction of the bundle size. The library does not have support for realtime reads or any offline abilities. It is ideal for users who use Firestore for one-time reads.
import { initializeApp } from 'firebase/app'; import { getFirestore, collection, getDocs } from 'firebase/firestore/lite'; const firebaseApp = initializeApp({ /* config */ }); const db = getFirestore(); const snapshot = await getDocs(collection('cities'));
Another benefit of Firestore Lite is that it can be used with the fully featured Firestore package. Some pages may only require single reads whereas some may need realtime streams. You have the option of using either (or both) in your web app where needed.
Moving away from the browser's global window object
Another significant development in the new SDK is the move towards JavaScript modules (ESM) and away from the browser's global window object.
window
Historically libraries have been loaded and managed via a namespace on the window, such as window.firebase. This technique does not allow for tree shaking and lacks other benefits of the JavaScript module system.
window.firebase
This release prioritizes usage of Firebase via JavaScript modules. We still provide support for the window via a CDN script for the compatibility library. However, we only recommend using it as a path to upgrading to the module based SDK.
Get started today
We are really excited about the new JavaScript SDK and we want to hear from you as well. We'll be watching and responding to our GitHub discussion board for any questions or comments. If you've seen any size reductions in your codebase and want to share, let us know!
The Firestore Emulator Requests Monitor allows you to see requests to your local Firestore Emulator in real-time, and drill down to the details of each request, such as method, path, and Firebase Security Rules evaluation. You can access the Requests Monitor right now from the Emulator UI if you have the latest Firebase CLI running. (If not, it's never too late to upgrade!)
Requests Monitor helps you understand your request traffic in detail, and puts Firebase Security Rules front and center (just like security should be in your production app). Ever wonder what collections are pulled in for the amazing pizza tracker feature in your app? Forgot about how that cute button is backed by 400 lines of code changes Firestore? Worried about changes to security rules breaking production apps? The Requests Monitor has answers to all of these questions, plus more!
First, start the Emulator Suite, then navigate to the Firestore tab in the Emulator UI and you'll be greeted with two views: the default "Data" view is the familiar data viewer and editor you know and love, and the "Requests" view is just a click away.
Each client request to the Firestore Emulator will be added to the table as a new row. For example, if you connect your app to the Firestore Emulator and create a new document, it will show as a CREATE request on the table in real time. This works regardless of which platform your app is on -- be it Android, iOS, web, or anything else. And if you ever forget to open this page before you make those requests, don't worry -- we've got you covered. The last few requests will be kept for you to review when you navigate to the Requests page.
CREATE
The Requests View is a great help in developing security rules. A checkmark indicates if the request has been allowed by your security rules; denials and errors are also displayed. If you follow best practices and keep your rules locked down as much as possible, you'll certainly see some denials when you develop new features, and those are the perfect opportunity to learn! To take the guesswork out of updating security rules, just click on any request to see the evaluation details view.
On this page, you'll see your current local security rules on the left, and some information about the specific request on the right. Statements that allow, deny, or error will be highlighted. You may also run into situations where the request is not yet covered by any of the allow statements and is thus denied by default. Ever wonder why a request is denied where it should be allowed, or the reverse? The panel on the right can help. You can see the existing resource, the would-be version of the document (i.e. request.resource) and other important fields in the request. If your goal is to modify the security rules to align with changes to your app, you can also use those fields as inspiration for new conditions that your rules should gate on.
resource
request.resource
While we're at it, you'll notice the security rules on the evaluation details page are not modifiable -- that's because they are snapshots at the time when the request happened. To make rules changes, just directly modify the firebase.rules file with your favorite editor or IDE and the Firebase CLI will automatically apply the changes to the Firestore Emulator. And if you make another request, it will show up in the table view as a different row with new rules and results. Sometimes, it may be helpful to compare the old and new rules and see differences in how they were evaluated.
firebase.rules
For those of you who are familiar with the Security Rules Playground in Firebase Console, you may miss the simulated requests feature here. But in the emulator world, there's no need to guess what a request should look like -- you can just simply make that request from your app using the Firestore SDK in your favorite programming language. The Request Monitor always shows you faithfully how that request is represented in Security Rules and the actual decision of your rules. Any client request is fair game -- even lists and queries that are hard to simulate in production. We think you will eventually get used to it and love this new interactive development workflow as much as we do.
While you enjoy the new Requests Monitor, just keep in mind that only client requests are shown in the table. Admin requests bypass any security rules and therefore don't appear in the list. Similarly, if your rules depend on other documents in the Firestore (e.g. get(...) or exists(...)), only the main request is shown but not the dependent fetches, even though those dependent fetches count towards your quotas and billing in production. Just remember emulated benchmarks are not an indicator of production in terms of performance or cost estimation.
get(...)
exists(...)
We've already heard some developers asking if this feature will also be available in Firebase Console. While we cannot say for sure, recording production requests will certainly create a huge challenge to your app's Firestore performance and security. Aaaand, well, you know, production is not the best place to test out changes, especially security-related changes. We recommend developing and testing locally before rolling out to production, and the Firebase Emulator Suite is always seeking ways to help.
With the Firestore Emulator and Requests Monitor, you can see your prototyping path more clearly. In fact, you have a better view into unit and integration testing as well: just make sure to keep the Monitor open and run your tests against the same (emulated) Project ID that your app connects to. You only need to deploy when you feel comfortable with your changes.
Feel free to play around with the Firestore Emulator Requests Monitor, and let us know what you think!
Recently we shared the story of how CrazyLabs, a casual and hypercasual publisher, used Firebase Remote Config to optimize their portfolio of apps at scale. While CrazyLabs had success automating their testing with the Remote Config API, Remote Config can also be a great tool for achieving fast results that have a direct impact on revenue.
Vinwap is an indie developer who helps users personalize their Android devices with “live” wallpaper apps, including Glitter Live Wallpaper Glitzy and 4D Parallax Wallpaper. They use AdMob to monetize their apps, and wanted to see if increasing their use of banner ads would help to increase revenue without alienating their existing users.
Check out our latest case study to see how Vinwap was able to increase revenue by 30% in only six days, and why Wojciech Stefanski, the founder of Vinwap, called Firebase “the go to analysis tool when introducing any new changes.”
Firebase has kept a stable JavaScript interface for around 5 years now. If you wrote the following line of code 5 years ago, it would still work today.
import firebase from 'firebase/app'; import 'firebase/auth'; firebase.initializeApp({ /* config */ }); const auth = firebase.auth(); auth.onAuthStateChanged(user => { // Check for user status });
No one wants to rewrite code for the sake of rewriting code. A stable experience is one of the top decision factors when you choose to invest in a library. We have always taken that seriously. Our dedication to a stable API has been an ongoing balance of maintaining existing patterns and adopting new techniques for a better performance and developer experience. But, as Firebase lands more features, the SDK itself becomes larger. In order to reduce size and fit the modern web, we decided to make changes that required a break in our longstanding API.
A modular approach
When the original Firebase library was authored in 2012 the window was the only way to emulate a module system in the browser. It was a common practice to attach a "namespace" for your library on the window, hence window.firebase.
Today we have a native module system in the browser. We have a rich ecosystem of JavaScript module bundlers like Rollup and Webpack that make it easy to efficiently package application code with library code. These tools work best when dealing with module based JavaScript code.
The benefit is an effect called "tree shaking", which has the ability to eliminate unused code from your application and the libraries you import.
Firebase is changing to follow a modular pattern that provides tree shaking and therefore better performance for your sites. This modular approach removes "side-effect" imports and isolates features as individual functions.
Take a look at the sample below.
import { initializeApp } from 'firebase/app'; import { getAuth, onAuthStateChanged } from 'firebase/auth'; const firebaseApp = initializeApp({ /* config */ }); const auth = getAuth(firebaseApp); onAuthStateChanged(auth, user => { // Check for user status });
In the snippet above there's a lot of new pieces, especially around the imports, but there's also a lot of familiarity. The biggest difference is the organization of the code. It all comes down to namespaces versus modules.
Namespaces and services
Firebase has been available as a JavaScript module for quite some time now. However, our commitment to backwards compatibility and a stable API has kept us from taking advantage of a module first approach. It's one thing to be used as a module, but it's another to actually be modular. Any library can work in a module system, but it takes a specific organization to get the benefits of modules.
Firebase has followed a namespace and service pattern.
const firestore = firebase.firestore(); const colRef = firestore.ref('cities');
In this sample firebase is a namespace that contains the firestore service. Other services like Firestore, Authentication, Remote Config, Realtime Database, and Messaging can all also live on the namespace. Each service is also a namespace as well. The firestore service has a set of methods attached, like collection().
collection()
Organizing code in this way has its benefits. It's mentally easier for developers to "dot chain" to see what's available on a service. This approach was also easier to package before JavaScript had a bonafide module system. As JavaScript modules entered mainstream development, Firebase adapted but without breaking the namespace and service pattern. This kept the library stable but did not take full advantage of what JavaScript modules offer. Take the following code sample into account.
Let's go through the sample above, nearly line by line.
import firebase from 'firebase/app'; import 'firebase/auth';
The code starts by importing the firebase/app and firebase/auth packages. Notice though that they're imported differently. The firebase/app package has an export that gives us methods like initializeApp. However, the firebase/auth package has no exports. This type of import has many names, but I'm going to refer to it as a side-effect import. The side-effect import does not have any exports and typically when used they augment something. What does that mean for Firebase in this example? That's the firebase export.
firebase/app
firebase/auth
initializeApp
firebase.initializeApp({ /* config */ }); const auth = firebase.auth();
It's hard to tell what a side-effect import does knowing exactly what that importing firebase/auth does. In this case firebase/auth augments the firebase export from `firebase/app` and creates the `firebase.auth` namespace. If firebase/auth was not imported there would be an error when accessing firebase/auth.
firebase
The sample goes on to monitor a user's status.
auth.onAuthStateChanged(user => { // Check for user status });
The onAuthStateChanged method is available because of the side-effect import that augments the firebase export. But as a side-effect, the rest of the features offered by Firebase Authentication are on the namespace, whether you are using them or not. The current page may not handle any sign-in logic, but all 9 of Firebase Auth's sign-in methods will be included in your bundle. This is because of the namespace pattern.
onAuthStateChanged
The ability to chain methods off of the auth namespace is easy to understand and works well with IDEs that provide code completion like VSCode. It does not work well with tree shaking because no current tools are able to detect which methods on the chain are not used or what parts of a side-effect import are not needed. This leads to sites and apps that include more JavaScript than necessary. At Firebase we decided to reorganize our libraries in a modular pattern that supports tree shaking and therefore a smaller footprint in your site.
The new modular library
The new library moves away from the namespace approach and instead towards isolating features in JavaScript functions. Functions are a great way of organizing code and to promote tree shaking. Functions are independent units of code that take in arguments and return new values. Take a look at the new version of the sample code shown above.
The first thing to notice is that this sample is similar to one shown above. The first sample was eight lines of code, this sample is 8 lines of code. Both samples use two packages and accomplish the same objective: monitor authentication state.
Again, let's go through nearly line by line.
import { initializeApp } from 'firebase/app'; import { getAuth, onAuthStateChanged } from 'firebase/auth';
The side-effect imports are gone. The firebase/auth package provides exports rather than augmenting the firebase namespace. Another thing to note is there is no longer a firebase namespace. The firebase/app package does not return a "catch-all" export that contains all the methods from the package. Instead the package exports individual functions. Tree shaking tools like Rollup know that if a function isn't used it doesn't get included in the final build. This is unlike the firebase namespace or side-effect import in the previous sample. Build tools have to include everything when code is organized in that fashion.
The ergonomics of functions are different from a namespace with a bunch of methods attached to it. This is where the new organization really starts to show.
const firebaseApp = initializeApp({ /* config */ }); const auth = getAuth(firebaseApp);
The main difference in the lines above is that there is no more chaining from firebaseApp.auth(). Instead there is a getAuth() function that takes in firebaseApp and returns an auth instance. This may seem strange at first, but it provides more clarity than a side-effect import. Previously, the side-effect import augmented the firebase namespace behind the scenes. It was not clear how an auth service was created and it did not allow for tree shaking. The getAuth() function returns an initialized auth service from the details needed from the firebaseApp. This is a clear process: call a function with an argument, get a result back.
firebaseApp.auth()
getAuth()
firebaseApp
Creating a service this way allows the rest of the features of the library to be tree shake-able as well. Methods are no longer chained. Services are passed as the first argument and the function then uses the details of the auth service to do the rest. The rest of the functions in the firebase/auth package work this way as well. The auth service is the first argument and then what specific function needs next. Passing the auth service allows the other functions to use the details they need without needing a "catch-all" service that contains all the methods.
This new modular approach strips out unused code and builds upon modern web features.
Upgrade one library at a time
We fully understand that this upgrade is a breaking change which requires you to update existing code. As you would imagine, we have a lot of code internally that uses the Firebase JavaScript library as well. We understood this pain point immediately and created the compatibility library.
The compatibility library provides you the same API as the previous library version (version 8), but uses the new version 9 library under the hood. This allows you to use the new API and the old at the same time as you upgrade your site.
The ability to use these APIs side by side gives you flexibility when upgrading.
import firebase from 'firebase/compat/app'; import 'firebase/compat/auth'; const firebaseApp = firebase.initializeApp({ /* config */ }); const auth = firebaseApp.auth(); auth.onAuthStateChanged(user => { // Check for user status });
The first thing to notice is that the only change needed was to change the import paths to the /compat/ entry point. From here you can add the new libraries.
/compat/
import firebase from 'firebase/compat/app'; import { getAuth } from 'firebase/auth'; import 'firebase/compat/auth'; const firebaseApp = firebase.initializeApp({ /* config */ }); const auth = getAuth(firebaseApp); auth.onAuthStateChanged(user => { // Check for user status });
In the snippet above, both Firebase Auth library versions are being used. This code works and builds just fine. However, we don't recommend you use both versions unless you are in the middle of an upgrade.
import firebase from 'firebase/compat/app'; import { getAuth, onAuthStateChanged } from 'firebase/auth'; const firebaseApp = firebase.initializeApp({ /* config */ }); const auth = getAuth(firebaseApp); onAuthStateChanged(auth, user => { // Check for user status });
The last step you'll take when upgrading is to upgrade firebase/app. While upgrading you will need to keep the namespace import from the firebase/compat/app library until each Firebase service has been upgraded to the new version.
firebase/compat/app
import { initializeApp } from 'firebase/app'; import { getAuth } from 'firebase/auth'; const firebaseApp = initializeApp({ /* config */ }); const auth = getAuth(firebaseApp); onAuthStateChanged(auth, user => { // Check for user status });
Once everything is upgraded, you won't have any dependencies left on the compatibility library and you'll start to see the full tree shakeable benefits.
Let us know what you think!
We are really excited about the future of this library and the performance benefits it can provide. This library is still in beta and we want to know what you think of these changes. Come visit us on our GitHub discussion board and let us know what you think, if you're seeing size reductions in your bundles or if you have any questions about upgrading.
A few months ago, at Google I/O, we announced the beta of App Check, Firebase’s new mobile and web API security solution. App Check is an additional layer of security that protects access to your services by attesting that incoming traffic is coming from your app, and blocking traffic that doesn't have valid credentials. Right now, App Check is available for Cloud Storage, Realtime Database, and Cloud Functions for Firebase. In case you missed the launch, check out our introduction video to see how App Check works.
Today, we’re happy to announce three new features we’ve added to the App Check beta: support for App Attest on iOS, configurable time-to-live values (TTLs) for tokens, and support for protecting non-Firebase backends with App Check.
We know how important security is, so we wanted to make sure we’re integrated with the latest app attestation providers for our main platforms, and that includes iOS. To that end, we’ve added support on iOS for App Attest, Apple’s app attestation technology that was recently featured at Apple’s WWDC conference.
App Attest can be used to assert that a request comes from a legitimate instance of your app that satisfies three conditions:
You can use App Attest as an App Check provider on any iOS device that supports it. On devices without App Attest support, you can continue to use DeviceCheck with App Check. See our developer guide to learn how to use App Check with App Attest on iOS.
To give you the power to choose how you want to balance security and usability in your app, we’ve added the optional ability to set the TTL of App Check tokens. By using a short TTL, you optimize for increased security; on the other hand, a longer TTL can improve responsiveness and minimize quota usage. You can even customize the TTL individually per attestation provider. Configurable TTLs are supported when using App Attest, Device Check, SafetyNet, reCAPTCHA v3, and custom providers.
If you use your own backend services alongside Firebase, App Check can still help you! With our newest beta, you can protect your non-Firebase resources with App Check. This protection is currently possible on any backend service or service proxy that can run the Firebase Admin SDK for Node.js, including Cloud Run & GKE instances, and even bare metal servers.
If you already use App Check with RTDB, Storage or Functions, it is now really easy to extend App Check’s protections to your own server as well. It only takes a few lines of code on the client and on the backend to start protecting your resources today. Take a look at our guides for iOS, Android, and web to learn how.
This is part of a series of articles about app quality. Here is an overview of all the other articles:
Apps and games have evolved rapidly in recent years, and user expectations for high performance have increased right alongside them. Today’s users don’t just demand speed and performance — they reward it. A 2019 study found that retail sites saw 8% more conversions when they reduced their mobile site load times by one-tenth of a second. And travel sites boosted conversions by just over 10%.
As you reach more users across different devices, locations, OS versions, and networks, optimizing performance becomes even more of a moving target. To understand the unique context behind performance issues, you need actionable insights about your app performance from a user's perspective. With performance data that allows you to spend less time putting out fires, you can devote more time to creating delightful experiences knowing that no bug or glitch will slip through the cracks.
With performance data that allows you to spend less time putting out fires, you can devote more time to creating delightful experiences knowing that no bug or glitch will slip through the cracks.
In this article, we’ll explore some Firebase Performance Monitoring features that can help you keep an eye on your app’s performance and understand the experience from a user's point of view.
Real-time app performance metrics
Releasing a new feature that performs well for every user — no matter their location, device, or network speed — can be challenging if you don’t have the timely information you need to gauge performance across a range of variables. When poor performance and low app ratings occur, you need clear insights to deliver an experience worthy of a 5-star review.
Firebase Performance Monitoring processes your app performance data in real time so you can monitor new releases during development and post-launch. For instance, you can gather performance data from Firebase Emulators or virtual devices on Firebase Test Lab to test your app locally before launch. And after launch, you can get insights about metrics related to screen rendering and network requests to learn how your app is performing among different user segments.
By learning how your app responds for different groups of users, you can quickly take action to fix any errors and ensure users won’t delete your app to find one that works better on their device.
Performance Monitoring dashboard highlighting real-time metrics
Customizable Metrics Board
In the first blog post of this series, we highlighted some standard app performance metrics to keep top-of-mind, such as app start-up time, screen rendering performance, and network performance. However, sometimes the influx of real-time data after a big release can feel overwhelming, and identifying where you should focus and take action can be a daunting task.
With the revamped Performance Monitoring dashboard, you can customize your app performance metrics board to highlight the most important metrics for your app. For example, if you’re releasing updates on a shopping app, you can select and track slow-rendering frames on the checkout screens. This helps ensure your customers are enjoying a seamless experience from start to finish. You can also break down your key metrics by country, device, app versions, and OS level for a deeper dive into your performance data.
By learning how quickly your app responds for different groups of users, you can take action to fix latency issues and ensure users won’t delete your app to find one that works better on their device.
Additionally, Performance Monitoring allows you to implement custom code traces, which help monitor the performance of your app between two points in time. You can also create your own traces to capture performance data associated with specific code in your app. For example, you could use custom code traces to measure how long it takes your app to load a set of images and make sure the graphics aren’t causing too much lag.
Compare performance between app versions
Retaining a diverse user base isn’t easy without understanding how specific user segments are engaging with your app — especially when their experience isn’t up to par. To make sure every new release performs at its best once it reaches a large number of users, you can use the new Performance Monitoring dashboard to identify app performance changes that need immediate attention.
The metrics board enables metric performance tracking across versions. If your latest release calls a new API at start-up, you can track latencies in app start time between the latest version of your app and previous versions. The traces table is especially helpful to understand how your traces are trending across selected time ranges. That means you no longer have to wait for app store reviews or support tickets to know when your app performance is lagging.
Performance Monitoring traces table
Track trends, regressions, and severe issues
One of the most important ways to grow and engage your audience is by constantly releasing new features and updates to your app. But any code or configuration changes to your app or any of its many dependencies carry a risk of degrading your app’s performance or causing issues with user experience. For example, if your e-commerce app makes dozens of API calls to fetch your catalog and product details, users might experience frustrating lags during their shopping experience.
By tracking trends and regressions with Performance Monitoring, you can quickly act on the most critical issues and get ahead of low ratings on the app store.
Improve user retention with Performance Monitoring
GameNexa Studios, an India-based app developer, seized an opportunity to invest in improving its app quality when their ad sales were disrupted by COVID-19. By combining Firebase Performance Monitoring and Firebase Crashlytics, the team gained actionable insights about its user base and improved their most popular app’s experience across the board. And by reducing the number of performance issues affecting its users, GameNexa ended up boosting both user retention and session duration, and increased in-app purchases by 2.5X.
Stay ahead of app stability and performance issues
To deliver the fast, consistent experience app that users expect, you need a strategy backed by tools that help you act quickly and fix significant issues on the fly. With detailed, actionable data and insights from Firebase, app developers and product managers can make smarter decisions before launch, tackle urgent issues swiftly after releasing an update, and quickly and confidently roll out new features that keep users coming back.
To get started with Firebase Performance Monitoring, integrate the Performance Monitoring SDK into your app and identify the metrics that matter most to your app’s success.