If you’ve used Firebase Remote Config, then you know how it can help you control and optimize your app on the fly. And recent improvements help you better visualize your configuration so you can more easily update your app to drive the outcomes you want, like increasing subscription sign-ups. But what if you have a portfolio of many apps that you want to optimize at the same time?
That was the goal of CrazyLabs, a hypercasual and casual publisher whose games, including Super Stylist - Makeover & Style Fashion Guru, Tie Dye, and Phone Case have been downloaded more than 4 billion times. Their business model relies on identifying potentially high-profit games early on among many applicants and helping them scale. CrazyLabs needed a solution that could help them test up to 30 configurations per title across up to 15 titles at a time in order to increase revenue without decreasing user engagement.
Learn how CrazyLabs used Remote Config and AdMob to optimize monetization at scale for all of their titles in our new case study.
Get ready for a new faster web experience with Firebase. For the longest time you all have asked us to optimize the size of our JavaScript libraries, and we've done just that. We've released brand new beta libraries that are significantly smaller in size. Some are even up to 80% smaller! We've managed to reduce the size all without removing any features from the previous version too!
How did we do this? We did it by embracing the modern web and its new features. We converted our library to take advantage of code elimination features of modern day JavaScript tools like webpack and Rollup. While this change drops size, it did require us to change the library's API for these tools to identify which functionality isn't being used in your app.
This is a breaking change that will require you to update your code. We have released the library to npm under the beta tag, but we will be publishing it to the main tag in the near future. You can get started today and use the compatibility library to make the upgrade easier.
beta
The new API
Take a look at our new beta API. The first thing you might notice is that we've removed all side-effect imports. You know, the import firebase/<service> lines of code, which aren't very clear about what exactly is being imported. Or as webpack succinctly puts it "A "side effect" is defined as code that performs a special behavior when imported, other than exposing one or more exports. An example of this are polyfills, which affect the global scope and usually do not provide an export."
import firebase/<service>
From now on in our API, we explicitly export each function from the package, which makes it clear what you are consuming in your app.
import { initializeApp } from 'firebase/app'; import { getAuth, onAuthStateChanged } from 'firebase/auth'; const firebaseApp = initializeApp({ /* config */ }); const auth = getAuth(); onAuthStateChanged(auth, user => { console.log(user); });
This new API has a lot of familiar functions from the previous one. The main difference is the organization of the code. We've removed all side-effect imports and created individual entry points for each and every package.
import { initializeApp } from 'firebase/app'; import { getFirestore, collection, getDocs } from 'firebase/firestore'; import { getAuth, onAuthStateChanged } from 'firebase/auth'; import { getStorage, uploadBytes } from 'firebase/storage'; import { getRemoteConfig, fetchAndActivate } from 'firebase/remote-config'; import { getRemoteConfig, fetchAndActivate } from 'firebase/remote-config'; import { getDatabase, ref, get } from 'firebase/database'; import { getMessaging, getToken } from 'firebase/messaging'; import { getPerformance } from 'firebase/performance'; import { getAnalytics, logEvent } from 'firebase/analytics';
Modern JavaScript tools like webpack and Rollup discourage the use of side-effect imports. This is because side-effect imports are like an unknown quantity. Module bundlers don't know what they are going to bring in. Having explicit functions to import gives these tools a better understanding of how to build your code.
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); });
When these tools can understand your code they can eliminate unused parts of a codebase, this is a feature called tree-shaking. This is what makes the new library so much smaller. By reorganizing the Firebase library we can take advantage of tree-shaking and remove all unneeded parts of the library from your app. This size savings we have seen have been significant.
How much smaller is the new library?
Let's get real for a second and talk library size. Firebase has always been a larger library on the web. The web itself is a balance of features and performance and we wanted to make that balance a lot easier for you. This was the biggest reason for us to take on tree shaking. We suspect that no matter what you'll see a sizable drop in your bundle size. However, we're hoping that with specific use cases you'll see significant size reductions.
The two biggest areas of improvement we have seen in our early studies are with the new firebase/firestore/lite package (more on that in a bit!) and firebase/auth. The table below shows a package, the current SDK version size, the current beta version size for a basic use case, and the percentage the SDK is lighter than the current v8 version.
firebase/firestore/lite
firebase/auth
You'll notice that authentication can be up to 72% lighter than before. When using firebase/firestore/lite you can save 84% from the current version of firebase/firestore if you only need one-time reads. This new "import only what you need" method allows you to decide what to include in your bundles and make that features and performance balance much easier.
firebase/firestore
Introducing Firestore Lite
Firestore is such a powerful library because it does so many things behind the scenes that we encourage you all to take for granted. Firestore has a complex caching, realtime streaming, persistent storage, multi-tab offline sync, retries, optimistic concurrency, and so much more. But we heard from you all that sometimes you just need to get a collection, and don't want to include all of Firestore's other features in your site. For those cases we wanted to make Firestore a simple and light solution, so we created a brand new subpackage: firebase/firestore/lite.
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'));
This sample uses firebase/app and the new firebase/firestore/lite package. You'll notice that calling getDocs() initiates a one-time data read. Firestore Lite allows you to create, read, update, and delete data with Firestore in a much smaller library. Realtime streaming is not included, but you can always switch back to firebase/firestore if that's what you need. If you want to adopt an advanced loading strategy, you can even load firestore/lite for a fast initial page load and lazy load firebase/firestore for progressive enhancement.
firebase/app
getDocs()
firestore/lite
Firestore Lite is significantly smaller. As you saw in the table above, it can be 84% lighter. We know that you Firestore users will find a great fit for this library.
An easier upgrade with our compatibility library
Change is never easy. Our new library provides new benefits but it's hard to go back and rewrite code that already works. To make that process easier, we're also releasing a compatibility library that allows you to port your code piece by piece.
import { initializeApp } from 'firebase/compat/app'; import 'firebase/auth/compat'; import { onAuthStateChanged } from 'firebase/auth'; const firebaseApp = firebase.initializeApp({ /* config */ }); const auth = firebaseApp.auth(); onAuthStateChanged(auth, user => { console.log(user); });
The new modular SDK cannot be used alongside the existing namespace based library, but the compatibility library allows you to use both APIs at the same time. You won't get all of the tree shaking advantages upfront, but once you match the new modular library you can switch off the compatibility library and rake in the savings.
What about framework integrations?
Libraries like AngularFire, ReactFire, and RxFire will be compatible with the new SDK in the near future. We are close to completing them, so hang tight! Track their progress in these issues on GitHub.
Once they have been updated there will be little to no work to move over, as we will update them underneath the hood. However, AngularFire will not initially receive all of the tree shaking benefits since it follows a classical OOP structure. We plan on releasing an API proposal in the near future to optimize for tree shaking and provide an easy path to upgrade as well.
Get started today
The new JavaScript library is available today on npm under the beta tag. We want to hear your feedback! Tell us what you think of the new API and any size savings you've seen. We're excited about the future of this library and the performance benefits it brings.
To learn more about the new library, see our talk at Google I/O. Also check out our upgrade guide for in-depth information about the upgrade process.
This is part of a series of articles about app quality. Here is an overview of all the other articles:
First impressions matter to app users. Even the most well-designed apps can fall flat if they don’t consistently deliver a crash-free experience.
Picture one of your app users getting ready to unwind after work. They grab a snack, get comfortable on the couch, and open their favorite gaming app … and it crashes. Or perhaps it freezes every time they’re on the brink of reaching the next level. These unstable experiences can frustrate users and may result in them uninstalling or leaving a scathing review on the app store.
In fact, quality issues are the most common reason for early app deletion. One in five users (19%) will uninstall an app due to technical errors or crashes.1
There are a handful of reasons for app crashes. A user’s device may have low memory or a weak chipset, or it may be running an earlier OS version. Alternatively, the app’s code may be filled with bugs. More importantly, as you add new features and acquire more users on different devices, you’re likely to encounter a wider variety of crashes behind the scenes.
Manually tracking, organizing, and fixing crashes can be a complex and time-consuming challenge. And even if you collect every bit of crash data, it can still be unclear what’s causing your app to crash or which errors are impacting the most users. That’s where having the right crash reporting tools makes all the difference.
Continually improving your app and launching new features is one of the best ways to increase retention and engage new and existing users. However, as your user base grows, splitting your time between releasing new features and monitoring the stability of new releases becomes a bit of a conundrum.
Real-time crash reporting in Firebase Crashlytics allows you to quickly triage and troubleshoot any bugs in your app by gathering and grouping crashes based on where they occurred in your app’s code. Groups of crashes are listed in order of frequency and degree of impact on users, making it easier to identify which issues to tackle and providing you with more time to build features that keep users engaged.
Crash report data displayed in the Firebase Crashlytics dashboard
To go even deeper into your crash data, you can enable BigQuery streaming export to identify prevalent issues and understand trends over time — such as which OS versions or specific devices are causing the most crashes. This helps you visualize your crash data and monitor issues that trigger alerts and custom workflows. Enabling BigQuery streaming also gives you the ability to analyze your data with BigQuery SQL, export it to another cloud provider, and use Google Data Studio to create custom dashboards and visualizations of crash trends.
Crashlytics integrated with BigQuery
For an app like Spotify — with more than 65 teams maintaining millions of lines of code per platform and launching new updates every week — moving fast and at scale is essential. To reduce stress on its development team before each launch, Spotify switched from manually tracking crashes every day to automating their release process using Crashlytics, primarily with BigQuery. Rather than having the team’s release manager on call to monitor each crash, Spotify now uses Crashlytics to track crashes for alpha and beta builds, set rules for incoming tickets, and assign tickets to the right teams.
Deliveroo, a food delivery company based in the U.K., similarly adopted Crashlytics and BigQuery to get ahead of crashes before they reach a certain threshold while tracking and analyzing performance data of each new release in real time. With the ability to create customized reports and separate errors, the development team drastically cut down on the time spent troubleshooting and reproducing app issues — and crash-free sessions increased from 99.35% to more than 99.7%.
Crashes don’t just turn away your existing app users — negative app reviews caused by an unstable session can also impact your ability to acquire new users. That’s why it’s crucial to know when and where crashes are happening.
Crashlytics velocity alerts notify you when a particular crash starts spiking so you can respond before the bug impacts more users. Velocity alerts are also configurable, giving you the power to set thresholds that determine when alerts should fire based on the percentage of user sessions being affected.
For instance, velocity alerts can detect major bugs during the rollout of a new release of your app or quickly alert you if there’s an issue impacting a large percentage of users. Velocity alerts will send an email or message on Slack, Jira, or PagerDuty, depending on which third-party integration you have enabled with your project.
Velocity alert settings in the Firebase Console
That’s exactly how Swiggy — one of India’s largest food delivery services — simultaneously monitors every app issue while focusing on the most significant ones first. Swiggy’s development team connected Crashlytics velocity alerts to PagerDuty and Jira to notify its on-call engineer whenever critical crashes reach a certain threshold. This allowed Swiggy to keep shipping fast with the confidence that they will be notified about high-priority crashes and low-priority crashes in the right manner.
Quickly identifying prevalent crashes is just one piece of the puzzle. By getting to the root cause, you can mitigate risk and avoid frustrating your app users by ensuring those crashes don’t happen again.
Crashlytics custom logs and keys record the events a user experienced during their session by tracking the state and sequence of their app. This gives you an actionable snapshot of what the user was doing leading up to the moment your app crashed. You can also define custom keys such as “installation_source”, “network,” and “language” to pinpoint exactly what happened before each crash — like whether a user installed your app on the Play Store or if they were connected to Wi-Fi — and reduce the time it takes to reproduce it.
And by using Crashlytics with Google Analytics, you can automatically capture predefined Google Analytics events — known as breadcrumbs — which enhances the data captured with custom logs and provides more detailed information on what caused a crash.
Breadcrumbs in Google Analytics
For mobile game publishers like Tapps Games, delivering a stable and immersive experience is crucial for keeping gamers engaged. Previously, Tapps would manually search through user reviews for negative feedback and then try to reproduce the crashes that users described. With Crashlytics' velocity alerts, the team was immediately notified when severe crashes were on the rise. After digging into the data, they realized an update to their Vlogger Go Viral game's video creation process and a simultaneous community player event was leading to consistent crashes.
Tapps Games’ development team jumped on a fix that helped boost their Google Play store rating from 3.9 to 4.7 and increased their crash-free users from 94.6% to 99.8%.
To grow your audience, keep users engaged, and spark positive reviews and recommendations, app stability needs to be a key focus area. Installing the Firebase Crashlytics SDK in your app gives you the tools and information you need to stay on top of critical issues.
In the third and final series of our guide, we’ll spotlight a set of tools you can use alongside Firebase Crashlytics to understand how your app is performing from a user's point of view.
Sources
Posted by the Firebase team
This is an introduction to a three part blog post series on app quality exploring how to unlock app stability and app performance for the optimal app experience. Find links to the other articles at the end of this blog post.
Stability and performance are the core of every successful app. Fast, crash-free experiences encourage users to stay engaged and drive positive reviews. That’s why keeping a close eye on your app’s stability is crucial for competing in today’s thriving app marketplace.
Users expect the best experience every time they interact with an app. And if bugs or latency issues get in the way, they’ll be quick to find a better option. Research has shown 88% of app users will abandon apps based on bugs and glitches. And within that group, 51% of users said they’d abandon an app completely if they experienced one or more bugs per day.
Not only is quality important to retaining users, but it’s important for attracting new users as well. If a large percentage of users are frustrated and your app store listing is filled with negative feedback about performance issues, you might have trouble acquiring new users.
In fact, 54% of users who left a 1-star review in the Play Store mentioned app stability and bugs.1
It’s no wonder that stability and performance are top areas of focus for developers. Our own Firebase research shows that a top need for developers is to obtain the tools and services that help them debug technical issues, trace issues back to changes in their code, and detect technical performance issues.
A large portion of the pre-launch development for a new app is spent squashing bugs and testing for potential issues. But getting your app ready for launch is just the first step — once it’s out in the world, maintaining your app’s health becomes an ongoing process as you create new features and iterate on previous versions.
It's important to remember that app quality isn’t one-size-fits-all. Depending on the type of app and how you define success, you’ll want to prioritize the factors that are crucial for your business. With Firebase’s customized reporting tools and real-time insights, you can hone in on the metrics that matter most.
For instance, in a productivity app — where users want a clean, simple interface and the ability to use it on the go — slow response time and high error rates will cause many users to drop off. Conversely, users might tolerate a bit of lag between menu screens in a food delivery app. But if it crashes every time they reach the checkout screen, your in-app revenue is sure to suffer.
No matter what type of app you have, here are a few of the most notable quality metrics that successful apps get right:
Monitoring metrics like these can mean the difference between driving downloads and retaining satisfied users versus seeing churn and negative reviews from dissatisfied users.
To stay ahead in such a dynamic app ecosystem, you need to know precisely where stability and performance issues occur in your app. In the next two blog posts of this series, we’ll spotlight two Firebase products that can help you detect crashes in your app and gather actionable insight about your app’s performance from a user’s perspective.
With Android App Bundles, you can separate your app into a base module and feature modules, allowing certain features of your app to be delivered conditionally or downloaded on demand. Each user of your app will receive only the code they need, when they need it.
As of the 28.0.0 release of the Firebase BoM, you can now use Firebase SDKs in feature modules of your app, not just your base module! This means you can reduce your app size if you're only using Firebase services in some of your modules.
For instance, imagine you have an app which uses Firebase Authentication for login and has an optional "chat with support" feature which uses Firebase Realtime Database. In a monolithic app structure, all of these features would be included in the base app module and delivered at install time:
With the latest version of the Firebase Android SDK, you could use feature modules to separate each feature. The signin feature would still be delivered at install time, since most users need to sign in. However, by moving the "chat with support" module to a feature module configured with on-demand delivery, it would be delivered only when the user needs it:
With this modular structure, your app's initial download size is much smaller. The feature module will defer downloading of not only the Realtime Database SDK, which is about 400kB, but also all the code, strings, resources, and assets needed to build the chat module.
To get started, just add the following dependency to your app's base module:
// base module dependencies { // Note: this library is not yet included in the Firebase BoM implementation 'com.google.firebase:firebase-dynamic-module-support:16.0.0-beta01' }
Then, you can add Firebase dependencies to feature modules and use them as you normally would.
// feature-signin module dependencies { implementation platform('com.google.firebase:firebase-bom:28.0.0') implementation 'com.google.firebase:firebase-auth' } // feature-chat module dependencies { implementation platform('com.google.firebase:firebase-bom:28.0.0') implementation 'com.google.firebase:firebase-database' }
By using a modular architecture, you can reduce the initial download size of your app and progressively enhance it with rich, Firebase-powered features as needed.
To read more about feature modules and how they work with the Firebase Android SDK, check out the documentation:
When we first began working on the Firebase Emulator Suite we dreamed of the day that every backend service in Firebase would have a local emulator. Today we can proudly say we're releasing another great emulator for Firebase Build products: the Cloud Storage for Firebase emulator.
The Cloud Storage for Firebase emulator integrates with the rest of the Firebase Emulator Suite, including the Firebase Auth emulator and the Cloud Functions emulator, unlocking the ability to locally test your app end-to-end like never before.
Just like the other components in the Firebase Emulator Suite, the Cloud Storage for Firebase emulator is part of the Firebase command-line interface which allows you to develop and test your app without connecting to production services.
The Cloud Storage for Firebase emulator supports the Web, Android, iOS and Admin (for Node.js) SDKs so regardless of where your app runs, you can use the new emulator.
The Cloud Storage for Firebase emulator supports all operations from the Web, iOS, and Android SDKs. This includes evaluating security rules, uploading and downloading files, and modifying metadata.
The emulator also supports all the most popular methods in the Firebase Admin SDK. This includes the same operations of uploading and downloading files along with metadata operations. If you're using more advanced Cloud Storage features which aren't supported, let us know. We'll continue to expand functionality over the coming months and your feedback will help us prioritize what to implement.
Make sure you update the Firebase CLI to at least version 9.11.0 and run the following command:
firebase init
Select Cloud Storage and the Emulators, when prompted, pick the Cloud Storage emulator. If this is a first time setup, you'll need to pick each Firebase product you need, such as Cloud Functions, Firestore and Realtime Database rules, as well as Hosting sites. Once everything you need is initialized, run the following command:
firebase emulators:start
This will start the Storage Emulator on localhost:9199 by default. Jump over to our documentation to connect your app to your new emulator!
Now that every Build product in Firebase has a local emulator, you can do the majority of your development entirely locally. We can't wait to see all the new stuff you'll build with your newly unlocked productivity. Make sure to send us a tweet and let us know what you make!