[{"data":1,"prerenderedAt":2899},["ShallowReactive",2],{"/blog/mobile-app-beta-testing-crash-reporting-tools-2026/":3,"/blog/mobile-app-beta-testing-crash-reporting-tools-2026/-related":706,"/blog/mobile-app-beta-testing-crash-reporting-tools-2026/-resources":2887},{"id":4,"title":5,"author":6,"body":10,"category":603,"createdAt":604,"description":605,"disclosure":606,"extension":607,"faq":608,"howTo":606,"location":624,"meta":625,"navigation":631,"ogImage":606,"path":632,"primaryKeyword":633,"readingTime":634,"related":635,"seo":640,"sources":641,"stem":696,"tags":697,"takeaways":698,"updatedAt":604,"url":704,"__hash__":705},"blog/blog/mobile-app-beta-testing-crash-reporting-tools-2026.md","HockeyApp, Fabric and App Center Are Gone: Beta Testing and Crash Reporting in 2026",{"name":7,"social":8},"Simon Dziak",{"twitter":9},"@SzymonDziak",{"type":11,"value":12,"toc":593},"minimark",[13,21,24,29,197,200,204,319,322,326,414,417,421,455,459,567,571,574],[14,15,16,20],"p",{},[17,18,19],"strong",{},"HockeyApp, Fabric, BuddyBuild and Visual Studio App Center are gone, and the old links to them lead nowhere."," In 2026 the simple answer is this: use TestFlight for iOS betas, Google Play testing tracks for Android betas, and Firebase Crashlytics or Sentry for crash reports. All of them have a free way in.",[14,22,23],{},"This guide replaces the \"alternatives to TestFlight\" lists that still point at dead sites. Dates come from the vendor's own announcement where one still exists. Limits and prices were checked on the vendor's pages on October 17, 2026.",[25,26,28],"h2",{"id":27},"what-shut-down-and-when","What shut down, and when",[30,31,32,51],"table",{},[33,34,35],"thead",{},[36,37,38,42,45,48],"tr",{},[39,40,41],"th",{},"Service",[39,43,44],{},"What happened",[39,46,47],{},"Date",[39,49,50],{},"Source",[52,53,54,84,103,129,154,177],"tbody",{},[36,55,56,63,66,69],{},[57,58,59,62],"td",{},[17,60,61],{},"HockeyApp"," (Microsoft)",[57,64,65],{},"Microsoft bought HockeyApp and planned to fold it into Application Insights. Accounts later moved to Visual Studio App Center. hockeyapp.net no longer loads",[57,67,68],{},"Bought December 11, 2014. Microsoft's post saying all accounts had moved to App Center is dated November 16, 2019",[57,70,71,78,79],{},[72,73,77],"a",{"href":74,"rel":75},"https://devblogs.microsoft.com/bharry/microsoft-acquires-hockeyapp/",[76],"nofollow","Microsoft",", ",[72,80,83],{"href":81,"rel":82},"https://devblogs.microsoft.com/appcenter/?p=39389",[76],"App Center blog",[36,85,86,91,94,97],{},[57,87,88,62],{},[17,89,90],{},"Visual Studio App Center",[57,92,93],{},"Retired, including build, test, distribution and CodePush. Analytics and Diagnostics were extended",[57,95,96],{},"March 31, 2025. Analytics and Diagnostics run until the end of March 2027",[57,98,99],{},[72,100,77],{"href":101,"rel":102},"https://learn.microsoft.com/en-us/appcenter/retirement",[76],[36,104,105,111,114,117],{},[57,106,107,110],{},[17,108,109],{},"Fabric"," (Twitter, then Google)",[57,112,113],{},"Google signed a deal to buy Fabric from Twitter and made Crashlytics the main crash reporter in Firebase. Fabric was then wound down. fabric.io now redirects to Firebase",[57,115,116],{},"Deal announced January 18, 2017. Wind-down announced September 14, 2018",[57,118,119,78,124],{},[72,120,123],{"href":121,"rel":122},"https://developers.googleblog.com/2017/01/welcoming-fabric-to-google.html",[76],"Google",[72,125,128],{"href":126,"rel":127},"https://venturebeat.com/business/google-is-killing-fabric-in-mid-2019-pushes-developers-to-firebase",[76],"VentureBeat",[36,130,131,136,139,142],{},[57,132,133],{},[17,134,135],{},"BuddyBuild",[57,137,138],{},"Apple bought it in January 2018 and stopped taking new customers. The service was shut down in 2021. buddybuild.com now redirects to Apple's Xcode Cloud page",[57,140,141],{},"Acquisition disclosed January 2, 2018. Shutdown reported March 1, 2021",[57,143,144,78,149],{},[72,145,148],{"href":146,"rel":147},"https://appleinsider.com/articles/21/03/01/buddybuild-shutting-down-3-years-after-apple-acquisition",[76],"AppleInsider",[72,150,153],{"href":151,"rel":152},"https://developer.apple.com/xcode-cloud/",[76],"Apple",[36,155,156,161,164,167],{},[57,157,158],{},[17,159,160],{},"TestFlight (the original, testflightapp.com)",[57,162,163],{},"Apple bought its parent company Burstly, built TestFlight into App Store Connect, and closed the old site. testflightapp.com no longer loads",[57,165,166],{},"Burstly bought in 2014. Old site closed at the end of February 2015",[57,168,169,78,173],{},[72,170,128],{"href":171,"rel":172},"https://venturebeat.com/technology/apple-snaps-up-testflight-parent-burstly-amid-product-shutdowns",[76],[72,174,148],{"href":175,"rel":176},"https://appleinsider.com/articles/15/01/26/apple-closing-independent-testflight-service-at-the-end-of-february",[76],[36,178,179,184,187,190],{},[57,180,181],{},[17,182,183],{},"Appsee",[57,185,186],{},"ServiceNow bought the team and technology, and the standalone product was shut down. appsee.com no longer loads. We found no official end-of-life date",[57,188,189],{},"Acquisition reported May 13, 2019",[57,191,192],{},[72,193,196],{"href":194,"rel":195},"https://siliconangle.com/2019/05/13/servicenow-picks-mobile-app-analytics-startup-appsee/",[76],"SiliconANGLE",[14,198,199],{},"We checked each old domain on October 17, 2026. The pattern repeats. A small developer-tools company is bought by a platform owner, the product is folded into something else, and the old URL dies. The tools you can rely on longest are the ones the platform owner builds for itself: TestFlight, Google Play and Crashlytics.",[25,201,203],{"id":202},"beta-distribution-in-2026","Beta distribution in 2026",[30,205,206,225],{},[33,207,208],{},[36,209,210,213,216,219,222],{},[39,211,212],{},"Option",[39,214,215],{},"Platforms",[39,217,218],{},"Tester limits",[39,220,221],{},"Cost",[39,223,224],{},"Notes",[52,226,227,246,265,283,300],{},[36,228,229,234,237,240,243],{},[57,230,231],{},[17,232,233],{},"TestFlight",[57,235,236],{},"iOS, iPadOS, macOS, tvOS, visionOS",[57,238,239],{},"100 internal testers (App Store Connect users). Up to 10,000 external testers. Each tester can use up to 30 devices",[57,241,242],{},"Included with Apple Developer Program membership",[57,244,245],{},"Builds expire after 90 days. The first build sent to an external group goes through Beta App Review. Later builds may not need a full review",[36,247,248,253,256,259,262],{},[57,249,250],{},[17,251,252],{},"Google Play internal testing",[57,254,255],{},"Android",[57,257,258],{},"Up to 100 testers, added by email",[57,260,261],{},"Included with a Play developer account",[57,263,264],{},"Fast to publish. Good for your own team",[36,266,267,272,274,277,280],{},[57,268,269],{},[17,270,271],{},"Google Play closed testing",[57,273,255],{},[57,275,276],{},"Email lists of up to 2,000 users each, up to 200 lists",[57,278,279],{},"Included",[57,281,282],{},"Personal accounts created after November 13, 2023 need a closed test with at least 12 testers opted in for 14 days before applying for production",[36,284,285,290,292,295,297],{},[57,286,287],{},[17,288,289],{},"Google Play open testing",[57,291,255],{},[57,293,294],{},"Unlimited, or a limit of at least 1,000",[57,296,279],{},[57,298,299],{},"Anyone can join from the Play listing",[36,301,302,307,310,313,316],{},[57,303,304],{},[17,305,306],{},"Firebase App Distribution",[57,308,309],{},"iOS and Android",[57,311,312],{},"The overview page does not state a tester limit",[57,314,315],{},"Listed as a no-cost product on Firebase pricing",[57,317,318],{},"Testers join by email or group. Distribute from the console, the CLI, fastlane or Gradle (Gradle is Android only). The docs do not state a build expiry, so check before you rely on one",[14,320,321],{},"Apple's published rule is that external testing needs Beta App Review for the first build. Allow time for it before you promise a date to a client.",[25,323,325],{"id":324},"crash-reporting-in-2026","Crash reporting in 2026",[30,327,328,343],{},[33,329,330],{},[36,331,332,334,337,340],{},[39,333,212],{},[39,335,336],{},"Free tier",[39,338,339],{},"First paid plan",[39,341,342],{},"Best for",[52,344,345,361,377,399],{},[36,346,347,352,355,358],{},[57,348,349],{},[17,350,351],{},"Firebase Crashlytics",[57,353,354],{},"Free. Firebase lists it as a no-cost product",[57,356,357],{},"None for Crashlytics. Other Firebase products are billed separately",[57,359,360],{},"Flutter, iOS and Android apps already on Firebase",[36,362,363,368,371,374],{},[57,364,365],{},[17,366,367],{},"Sentry",[57,369,370],{},"Developer plan: 5k errors, 1 user, 30 days of data, 5M tracing spans",[57,372,373],{},"Team plan, $29 a month billed monthly, or $26 a month billed annually",[57,375,376],{},"Teams that also want web and backend errors, tracing and session replay",[36,378,379,385,388,396],{},[57,380,381,384],{},[17,382,383],{},"Bugsnag"," (SmartBear)",[57,386,387],{},"Free plan: 1 user, 7.5K events and 1M spans a month, 7 days of data",[57,389,390,391],{},"See ",[72,392,395],{"href":393,"rel":394},"https://www.bugsnag.com/pricing",[76],"bugsnag.com/pricing",[57,397,398],{},"Teams that want stability scores per release",[36,400,401,406,409,411],{},[57,402,403],{},[17,404,405],{},"Azure Monitor and other APM tools",[57,407,408],{},"See each vendor",[57,410,408],{},[57,412,413],{},"Teams already on Azure. Microsoft's App Center notice names Datadog, Dynatrace and New Relic, and an Azure Monitor mobile option in public preview",[14,415,416],{},"On Bugsnag, the pricing page lists its paid plans as Select, Preferred and Enterprise and carries a SmartBear copyright. We could not read a clear first paid price, so we do not quote one.",[25,418,420],{"id":419},"how-to-choose","How to choose",[422,423,424,431,437,443,449],"ol",{},[425,426,427,430],"li",{},[17,428,429],{},"You only need to hand a build to a client or a few testers."," TestFlight for iOS and Play internal testing for Android. They are free, official and unlikely to disappear.",[425,432,433,436],{},[17,434,435],{},"You want one tool for both platforms."," Firebase App Distribution lets you send one invite flow for iOS and Android builds. You still need to follow Apple's rules for installing on test devices.",[425,438,439,442],{},[17,440,441],{},"Your app is already on Firebase."," Use Crashlytics. It is free and sits in the same console as your auth, database and messaging.",[425,444,445,448],{},[17,446,447],{},"You also run a website or an API."," Sentry puts mobile, web and server errors in one place. Check the free limits against your traffic first, because 5k errors a month goes fast on a noisy app.",[425,450,451,454],{},[17,452,453],{},"You were burned by a shutdown."," Keep your build pipeline in files you own (fastlane or plain scripts), keep release notes in your repo, and pick tools run by Apple, Google or a company whose main product is that tool.",[25,456,458],{"id":457},"setup-checklist-for-a-flutter-app","Setup checklist for a Flutter app",[422,460,461,467,473,488,514,534,555,561],{},[425,462,463,466],{},[17,464,465],{},"Apple side."," Create the app in App Store Connect, add internal testers, then upload a build from Xcode or fastlane. Add an external group only when you are ready for Beta App Review.",[425,468,469,472],{},[17,470,471],{},"Google side."," Create the app in Play Console and upload an app bundle to the internal testing track. Add testers by email and share the opt-in link.",[425,474,475,478,479,483,484,487],{},[17,476,477],{},"Pick one crash reporter."," Both have official Flutter packages. As of October 17, 2026, ",[480,481,482],"code",{},"firebase_crashlytics"," is at version 6.0.0 and ",[480,485,486],{},"sentry_flutter"," is at version 10.1.0 on pub.dev.",[425,489,490,493,494,497,498,501,502,505,506,509,510,513],{},[17,491,492],{},"Crashlytics route."," Run ",[480,495,496],{},"flutter pub add firebase_crashlytics firebase_analytics",", then ",[480,499,500],{},"flutterfire configure",". Set ",[480,503,504],{},"FlutterError.onError"," to ",[480,507,508],{},"FirebaseCrashlytics.instance.recordFlutterFatalError",", and ",[480,511,512],{},"PlatformDispatcher.instance.onError"," for async errors.",[425,515,516,493,519,522,523,525,526,529,530,533],{},[17,517,518],{},"Sentry route.",[480,520,521],{},"npx @sentry/wizard@latest -i flutter",". It adds ",[480,524,486],{}," and ",[480,527,528],{},"sentry_dart_plugin"," and patches ",[480,531,532],{},"main.dart",". As of October 17, 2026, Sentry's docs list Flutter 3.44.0 and Dart 3.12.0 or later.",[425,535,536,539,540,543,544,547,548,551,552,554],{},[17,537,538],{},"Upload symbols."," If you build with ",[480,541,542],{},"--split-debug-info"," or ",[480,545,546],{},"--obfuscate",", upload the symbols or the stack traces will be unreadable. For Crashlytics on Android, run ",[480,549,550],{},"firebase crashlytics:symbols:upload --app=FIREBASE_APP_ID PATH/TO/symbols",". On iOS, Firebase says Flutter 3.12.0 or later with Crashlytics plugin 3.3.4 or later can generate and upload the dSYMs for you. For Sentry, use ",[480,553,528],{},".",[425,556,557,560],{},[17,558,559],{},"Force a test crash in a release build,"," not only in debug, and confirm it shows up readable in the dashboard.",[425,562,563,566],{},[17,564,565],{},"Write down who gets the alert."," A crash report nobody reads is the same as having none.",[25,568,570],{"id":569},"need-a-hand","Need a hand?",[14,572,573],{},"App369 is Simon Dziak's studio. He builds and runs Workspace369, a production Flutter and Firebase SaaS.",[575,576,577,585],"ul",{},[425,578,579,580,584],{},"A crash or a build that fails on one platform: the ",[72,581,583],{"href":582},"/fixed-price/flutter-firebase-bug-fix/","App Fix Ticket"," diagnoses one issue for $450 (3 business days) and fixes it for $1,200 (5 business days), both fixed price.",[425,586,587,588,592],{},"Cost problems on Firebase: the ",[72,589,591],{"href":590},"/fixed-price/firebase-cost-audit/","Firebase Cost-Cut Audit",", $750 fixed price, 5 business days.",{"title":594,"searchDepth":595,"depth":595,"links":596},"",2,[597,598,599,600,601,602],{"id":27,"depth":595,"text":28},{"id":202,"depth":595,"text":203},{"id":324,"depth":595,"text":325},{"id":419,"depth":595,"text":420},{"id":457,"depth":595,"text":458},{"id":569,"depth":595,"text":570},"AI & Technology","2026-10-17T12:00:00.000Z","HockeyApp, Fabric, BuddyBuild, Appsee and Visual Studio App Center are gone or going. A dated record of what shut down, plus the 2026 options for mobile beta testing (TestFlight, Google Play, Firebase App Distribution) and crash reporting (Crashlytics, Sentry, Bugsnag), checked October 17, 2026.",null,"md",[609,612,615,618,621],{"question":610,"answer":611},"What replaced HockeyApp?","Microsoft moved HockeyApp users to Visual Studio App Center, and App Center was then retired on March 31, 2025. For beta distribution, Microsoft itself points to Apple TestFlight for iOS and Google Play testing for Android. For crash reporting, the common replacements are Firebase Crashlytics and Sentry.",{"question":613,"answer":614},"What replaced Fabric and Crashlytics Beta?","Google bought Fabric from Twitter (announced January 18, 2017) and moved Crashlytics into Firebase. Firebase Crashlytics handles crash reporting and is free. Firebase App Distribution handles beta builds and is also listed as no-cost.",{"question":616,"answer":617},"Is TestFlight free?","Yes. TestFlight comes with an Apple Developer Program membership. You can invite up to 100 internal testers and up to 10,000 external testers, and a build can be tested for up to 90 days. The first build you send to external testers goes through Beta App Review.",{"question":619,"answer":620},"What is the best free crash reporting tool for a mobile app?","Firebase Crashlytics is free and works well for Flutter, iOS and Android apps. Sentry has a free Developer plan (5k errors a month, 1 user) and is a good fit if you also want web and backend errors in one place.",{"question":622,"answer":623},"Does Google Play have beta testing like TestFlight?","Yes. Google Play has internal testing (up to 100 testers), closed testing (email lists of up to 2,000 users each) and open testing. Personal developer accounts created after November 13, 2023 must run a closed test with at least 12 testers for 14 days before applying for production access.","Boynton Beach, FL",{"readingTimeStats":626},{"text":627,"minutes":628,"time":629,"words":630},"6 min read",5.745,344700,1149,true,"/blog/mobile-app-beta-testing-crash-reporting-tools-2026","hockeyapp alternative","8 min",[636,637,638,639],"parse-kinvey-backend-as-a-service-alternatives-2026","firebase-dynamic-links-shutdown-deep-linking-2026","how-to-debug-a-flutter-firebase-bug-2026","flutter-ios-build-failed-after-upgrade-2026",{"title":5,"description":605},[642,644,646,648,650,652,654,656,658,660,662,665,668,671,674,676,679,682,685,688,690,693],{"title":643,"url":101},"Microsoft, Visual Studio App Center retirement",{"title":645,"url":74},"Brian Harry (Microsoft), \"Microsoft acquires HockeyApp\" (December 11, 2014)",{"title":647,"url":81},"Microsoft App Center blog, \"HockeyApp is being retired\" (November 16, 2019)",{"title":649,"url":121},"Google Developers Blog, \"Welcoming Fabric to Google\" (January 18, 2017)",{"title":651,"url":126},"VentureBeat, \"Google is killing Fabric in mid-2019\" (September 14, 2018)",{"title":653,"url":146},"AppleInsider, Buddybuild shutting down 3 years after Apple acquisition (March 1, 2021)",{"title":655,"url":151},"Apple, Xcode Cloud (where buddybuild.com now redirects)",{"title":657,"url":175},"AppleInsider, Apple closing independent TestFlight service (January 2015)",{"title":659,"url":171},"VentureBeat, Apple snaps up TestFlight parent Burstly (2014)",{"title":661,"url":194},"SiliconANGLE, ServiceNow picks up mobile app analytics startup Appsee (May 13, 2019)",{"title":663,"url":664},"Apple, TestFlight overview (App Store Connect Help)","https://developer.apple.com/help/app-store-connect/test-a-beta-version/testflight-overview/",{"title":666,"url":667},"Apple, TestFlight","https://developer.apple.com/testflight/",{"title":669,"url":670},"Google Play Console Help, Set up an open, closed or internal test","https://support.google.com/googleplay/android-developer/answer/9845334",{"title":672,"url":673},"Google Play Console Help, App testing requirements for new personal developer accounts","https://support.google.com/googleplay/android-developer/answer/14151465",{"title":306,"url":675},"https://firebase.google.com/docs/app-distribution",{"title":677,"url":678},"Firebase pricing","https://firebase.google.com/pricing",{"title":680,"url":681},"Firebase Crashlytics for Flutter, get started","https://firebase.google.com/docs/crashlytics/flutter/get-started",{"title":683,"url":684},"Sentry pricing","https://sentry.io/pricing/",{"title":686,"url":687},"Sentry for Flutter","https://docs.sentry.io/platforms/dart/guides/flutter/",{"title":689,"url":393},"Bugsnag pricing (SmartBear)",{"title":691,"url":692},"firebase_crashlytics on pub.dev","https://pub.dev/packages/firebase_crashlytics",{"title":694,"url":695},"sentry_flutter on pub.dev","https://pub.dev/packages/sentry_flutter","blog/mobile-app-beta-testing-crash-reporting-tools-2026","hockeyapp alternative, fabric alternative, app center alternative, testflight alternatives, beta testing tools, crash reporting tools, firebase crashlytics, sentry flutter, buddybuild, appsee, mobile app beta testing",[699,700,701,702,703],"HockeyApp, Fabric, BuddyBuild, Appsee and the original TestFlight site are all gone. As of October 17, 2026, hockeyapp.net, appsee.com and testflightapp.com no longer load a working site, fabric.io redirects to Firebase and buddybuild.com redirects to Apple Xcode Cloud.","Visual Studio App Center was retired on March 31, 2025. Its Analytics and Diagnostics features run until the end of March 2027.","For beta distribution, TestFlight (iOS) and Google Play testing tracks (Android) are free and cover most teams. Firebase App Distribution is a no-cost option that handles both platforms.","For crash reporting, Firebase Crashlytics is free. Sentry has a free Developer plan and its Team plan starts at $29 a month billed monthly.","Whatever you pick, upload your symbol files (dSYMs on iOS, split-debug-info symbols for Flutter). Without them, crash reports are unreadable.","https://app369.com/blog/mobile-app-beta-testing-crash-reporting-tools-2026/","ULM0ZGkMidTn63UWNC33h9T9a2yWxH8d49GQWNzwBDc",[707,1187,1968,2377],{"id":708,"title":709,"author":710,"body":712,"category":603,"createdAt":604,"description":1121,"disclosure":606,"extension":607,"faq":1122,"howTo":606,"location":624,"meta":1135,"navigation":631,"ogImage":606,"path":1141,"primaryKeyword":1142,"readingTime":1143,"related":1144,"seo":1148,"sources":1149,"stem":1177,"tags":1178,"takeaways":1179,"updatedAt":604,"url":1185,"__hash__":1186},"blog/blog/parse-kinvey-backend-as-a-service-alternatives-2026.md","Parse, Kinvey and Realm Sync Are Gone: Where to Run Your App Backend in 2026",{"name":7,"social":711},{"twitter":9},{"type":11,"value":713,"toc":1114},[714,720,723,725,861,864,868,1006,1009,1011,1043,1047,1050,1088,1090,1093],[14,715,716,719],{},[17,717,718],{},"If your app was built on Parse, Kinvey, Telerik Platform or Realm Sync, that backend is gone, and links to the old docs now lead nowhere."," In 2026, the realistic homes for a mobile app backend are Firebase, Supabase, Parse Server (self-hosted or hosted on Back4App), Appwrite and PocketBase. The safest choice is the one you could leave, because every service on the list below was once someone's safe choice.",[14,721,722],{},"This guide replaces the migration posts and vendor pages that used to answer \"where do I go after Parse?\" Every date below comes from the vendor's own announcement, and every price was checked on the vendor's pricing page on October 17, 2026.",[25,724,28],{"id":27},[30,726,727,739],{},[33,728,729],{},[36,730,731,733,735,737],{},[39,732,41],{},[39,734,44],{},[39,736,47],{},[39,738,50],{},[52,740,741,762,783,803,824,840],{},[36,742,743,749,752,755],{},[57,744,745,748],{},[17,746,747],{},"Parse"," (Facebook)",[57,750,751],{},"Hosted service retired after a one-year wind-down. Parse Server and a database migration tool were released as open source.",[57,753,754],{},"Announced January 28, 2016. Retired January 28, 2017",[57,756,757],{},[72,758,761],{"href":759,"rel":760},"https://web.archive.org/web/20160128222249/http://blog.parse.com/announcements/moving-on/",[76],"Parse blog, \"Moving On\"",[36,763,764,770,773,776],{},[57,765,766,769],{},[17,767,768],{},"Kinvey"," (Progress)",[57,771,772],{},"Bought by Progress. Today kinvey.com has no website address in DNS, and progress.com/kinvey redirects to a community page that returns a 404",[57,774,775],{},"Acquisition announced June 28, 2017. Links checked October 17, 2026",[57,777,778],{},[72,779,782],{"href":780,"rel":781},"https://www.progress.com/blogs/progress-acquires-the-leading-provider-of-backend-as-a-service",[76],"Progress",[36,784,785,790,793,796],{},[57,786,787,769],{},[17,788,789],{},"Telerik Platform and AppBuilder",[57,791,792],{},"Retired, with a notice telling users how to recover their apps and data",[57,794,795],{},"May 10, 2018",[57,797,798],{},[72,799,802],{"href":800,"rel":801},"https://www.npmjs.com/package/appbuilder",[76],"Progress notice on npm",[36,804,805,811,814,817],{},[57,806,807,810],{},[17,808,809],{},"Atlas Device Sync and Realm-based Device SDKs"," (MongoDB)",[57,812,813],{},"Deprecated, then removed. The on-device database continues as open source, without sync",[57,815,816],{},"Deprecated September 2024. Removed September 30, 2025",[57,818,819],{},[72,820,823],{"href":821,"rel":822},"https://www.mongodb.com/docs/atlas/device-sdks/deprecation/",[76],"MongoDB",[36,825,826,830,833,835],{},[57,827,828,62],{},[17,829,90],{},[57,831,832],{},"Retired, including the hosted CodePush service. Analytics and Diagnostics are extended",[57,834,96],{},[57,836,837],{},[72,838,77],{"href":101,"rel":839},[76],[36,841,842,848,851,854],{},[57,843,844,847],{},[17,845,846],{},"Firebase Dynamic Links"," (Google)",[57,849,850],{},"Shut down. Clicked links now return a 404",[57,852,853],{},"August 25, 2025",[57,855,856],{},[72,857,860],{"href":858,"rel":859},"https://firebase.google.com/support/dynamic-links-faq",[76],"Firebase FAQ",[14,862,863],{},"The pattern is the same each time. A hosted service that is not the vendor's main business gets folded into something else or switched off, often with a year or more of notice. Apps that kept their data in standard formats, and their logic in their own code, moved in weeks. Apps that leaned on vendor-only features had to be rebuilt.",[25,865,867],{"id":866},"the-2026-options-compared","The 2026 options compared",[30,869,870,891],{},[33,871,872],{},[36,873,874,877,880,883,886,889],{},[39,875,876],{},"Backend",[39,878,879],{},"Database",[39,881,882],{},"Open source",[39,884,885],{},"Free tier (checked October 17, 2026)",[39,887,888],{},"First paid tier",[39,890,342],{},[52,892,893,915,937,958,984],{},[36,894,895,900,903,906,909,912],{},[57,896,897],{},[17,898,899],{},"Firebase",[57,901,902],{},"Firestore (NoSQL)",[57,904,905],{},"No",[57,907,908],{},"Spark plan, no payment method needed. Firestore: 1 GiB stored, 50K reads, 20K writes and 20K deletes a day",[57,910,911],{},"Blaze, pay as you go (Spark's free usage is included)",[57,913,914],{},"Google-managed apps, push via FCM, offline-first mobile",[36,916,917,922,925,928,931,934],{},[57,918,919],{},[17,920,921],{},"Supabase",[57,923,924],{},"PostgreSQL",[57,926,927],{},"Yes (Apache-2.0)",[57,929,930],{},"500 MB database, 50,000 monthly active users, 2 active projects, paused after 1 week of inactivity",[57,932,933],{},"Pro from $25 a month, including $10 of compute credit",[57,935,936],{},"SQL data, row-level security, teams who may self-host later",[36,938,939,944,947,949,952,955],{},[57,940,941],{},[17,942,943],{},"Parse Server",[57,945,946],{},"MongoDB 7–8 or PostgreSQL 16–18",[57,948,927],{},[57,950,951],{},"Free to self-host. Back4App's hosted free plan: 25K requests a month, 250 MB of data, 1 GB of files",[57,953,954],{},"Back4App MVP at $15 per app a month, billed annually",[57,956,957],{},"Old Parse apps, and teams who want the Parse SDKs",[36,959,960,965,968,971,974,981],{},[57,961,962],{},[17,963,964],{},"Appwrite",[57,966,967],{},"Its own database API",[57,969,970],{},"Yes (BSD-3-Clause)",[57,972,973],{},"Free cloud plan, or self-host",[57,975,390,976],{},[72,977,980],{"href":978,"rel":979},"https://appwrite.io/pricing",[76],"appwrite.io/pricing",[57,982,983],{},"Self-hosted auth, database, storage and functions in one box",[36,985,986,991,994,997,1000,1003],{},[57,987,988],{},[17,989,990],{},"PocketBase",[57,992,993],{},"SQLite, in one Go binary",[57,995,996],{},"Yes (MIT)",[57,998,999],{},"Self-host only",[57,1001,1002],{},"Your own server",[57,1004,1005],{},"Small apps, internal tools, prototypes",[14,1007,1008],{},"Two notes on that table. Parse Server is very much alive: the Parse community shipped version 9.10.5 on October 16, 2026, and it runs on Node.js 22 and 24 (Node 20 reached end of life in April 2026). PocketBase is still pre-1.0 (v0.40.5, released October 8, 2026), so expect breaking changes between versions.",[25,1010,420],{"id":419},[422,1012,1013,1019,1025,1031,1037],{},[425,1014,1015,1018],{},[17,1016,1017],{},"You have an old Parse app."," Run Parse Server. Your client SDK calls keep working with few code changes, which was the whole point of the open-source release. Self-host it if you have someone to run MongoDB or PostgreSQL. Otherwise use a hosted Parse provider.",[425,1020,1021,1024],{},[17,1022,1023],{},"You are starting a new mobile app and want the least operations work."," Firebase or Supabase. Choose Firebase for NoSQL documents, Firebase Cloud Messaging and offline persistence. Choose Supabase if your data is relational, if you want SQL, or if you might self-host later.",[425,1026,1027,1030],{},[17,1028,1029],{},"You are leaving Realm Device Sync."," Keep the open-source on-device database if you only needed local storage. If you needed sync, move to a backend that syncs, then test offline edits, conflict handling and reconnects on real devices before you switch users over.",[425,1032,1033,1036],{},[17,1034,1035],{},"You must keep data on your own servers."," Appwrite or Parse Server for a full backend, PocketBase for a small one.",[425,1038,1039,1042],{},[17,1040,1041],{},"You were burned by a shutdown before."," Prefer open source, standard databases (PostgreSQL, MongoDB) and your own domain for every URL your app depends on. Firebase Dynamic Links showed that links on a vendor's domain die with the vendor's product.",[25,1044,1046],{"id":1045},"migrating-off-a-dead-or-dying-backend","Migrating off a dead or dying backend",[14,1048,1049],{},"A backend migration is usually smaller than it looks, if you do it in this order:",[422,1051,1052,1058,1064,1070,1076,1082],{},[425,1053,1054,1057],{},[17,1055,1056],{},"List what the old backend actually did."," Sign-in methods, database tables or collections, file storage, push notifications, scheduled jobs, server-side code (Parse called it Cloud Code) and any webhooks. This list is your scope.",[425,1059,1060,1063],{},[17,1061,1062],{},"Export the data first."," Move the records into a database you control, then point the old API at it if you still can. Parse's own migration tool worked this way, with no downtime.",[425,1065,1066,1069],{},[17,1067,1068],{},"Move files separately."," File storage is often not part of a database export. Copy the files and rewrite their URLs.",[425,1071,1072,1075],{},[17,1073,1074],{},"Plan sign-in carefully."," Find out whether password hashes can be exported and imported. If they can't, users will have to reset their passwords, so tell them in advance.",[425,1077,1078,1081],{},[17,1079,1080],{},"Rebuild server-side code as functions."," Cloud Functions on Firebase, Edge Functions on Supabase, Cloud Code on Parse Server.",[425,1083,1084,1087],{},[17,1085,1086],{},"Ship an app update that talks to the new backend, then switch off the old one."," Keep the old endpoints read-only for one release cycle, because some users update late.",[25,1089,570],{"id":569},[14,1091,1092],{},"App369 is Simon Dziak's studio. He builds and runs Workspace369, a production Flutter and Firebase SaaS, so this advice comes from running a live backend, not from a vendor brochure.",[575,1094,1095,1101,1109],{},[425,1096,1097,1098,1100],{},"An app that broke when its backend changed: the ",[72,1099,583],{"href":582}," diagnoses one issue for $450 and fixes it for $1,200, both fixed price.",[425,1102,1103,1104,1108],{},"Moving data or connecting a new backend to Stripe, a CRM or another system: ",[72,1105,1107],{"href":1106},"/fixed-price/api-integration/","API Integration",", $1,200 fixed price, 5 business days.",[425,1110,1111,1112,592],{},"Already on Firebase and the bill is climbing: the ",[72,1113,591],{"href":590},{"title":594,"searchDepth":595,"depth":595,"links":1115},[1116,1117,1118,1119,1120],{"id":27,"depth":595,"text":28},{"id":866,"depth":595,"text":867},{"id":419,"depth":595,"text":420},{"id":1045,"depth":595,"text":1046},{"id":569,"depth":595,"text":570},"Parse, Kinvey, Telerik Platform, Realm Sync and App Center are gone. A dated record of what shut down, plus the 2026 options for your app backend (Firebase, Supabase, Parse Server, Appwrite, PocketBase) with prices checked October 17, 2026.",[1123,1126,1129,1132],{"question":1124,"answer":1125},"What replaced Parse after it shut down?","Facebook open-sourced Parse Server when it announced the shutdown on January 28, 2016. It is still maintained by the Parse community (version 9.10.5 shipped October 16, 2026) and runs on Node.js with MongoDB or PostgreSQL. You can self-host it or use a hosted Parse provider such as Back4App.",{"question":1127,"answer":1128},"Is Kinvey still available?","Not at its old address. Progress announced it had acquired Kinvey on June 28, 2017. On October 17, 2026, kinvey.com had no website address in DNS, and progress.com/kinvey redirected to a community page that returned a 404. If an app still depends on Kinvey, plan a migration now.",{"question":1130,"answer":1131},"What should I use instead of Realm Device Sync?","MongoDB ended Atlas Device Sync on September 30, 2025. The Realm on-device database continues as open source without sync. For a synced backend, Firebase (Firestore with offline persistence) and Supabase are the common replacements. Test offline behaviour in your own app before you commit.",{"question":1133,"answer":1134},"Firebase or Supabase for a new mobile app?","Firebase if you want Google-managed NoSQL, push notifications and a free Spark plan with no payment method. Supabase if you want PostgreSQL, SQL queries and an open-source stack you can self-host. Supabase Pro starts at $25 a month, and Firebase Blaze is pay as you go.",{"readingTimeStats":1136},{"text":1137,"minutes":1138,"time":1139,"words":1140},"5 min read",4.915,294900,983,"/blog/parse-kinvey-backend-as-a-service-alternatives-2026","parse alternatives","9 min",[1145,1146,1147],"how-to-cut-your-firebase-bill-2026","firebase-security-guide-2026","supabase-permission-denied-new-tables-october-30-2026",{"title":709,"description":1121},[1150,1152,1155,1157,1159,1161,1163,1164,1165,1168,1171,1174],{"title":1151,"url":759},"Parse blog, \"Moving On\" (January 28, 2016), Wayback Machine copy",{"title":1153,"url":1154},"Parse Server on GitHub (releases, supported databases)","https://github.com/parse-community/parse-server",{"title":1156,"url":780},"Progress, \"Progress Acquires the Leading Provider of Backend-as-a-Service\" (June 28, 2017)",{"title":1158,"url":800},"Progress, Telerik Platform retirement notice on the appbuilder npm package",{"title":1160,"url":821},"MongoDB, Atlas Device SDKs deprecation",{"title":1162,"url":858},"Firebase Dynamic Links FAQ (shutdown date)",{"title":643,"url":101},{"title":677,"url":678},{"title":1166,"url":1167},"Supabase pricing","https://supabase.com/pricing",{"title":1169,"url":1170},"Back4App backend pricing","https://www.back4app.com/pricing/backend-as-a-service",{"title":1172,"url":1173},"Appwrite on GitHub","https://github.com/appwrite/appwrite",{"title":1175,"url":1176},"PocketBase on GitHub","https://github.com/pocketbase/pocketbase","blog/parse-kinvey-backend-as-a-service-alternatives-2026","parse alternatives, parse.com, kinvey alternatives, telerik platform, backend as a service, baas, parse server, firebase vs supabase, realm device sync end of life, mbaas, mobile backend",[1180,1181,1182,1183,1184],"Parse was retired on January 28, 2017. Its open-source successor, Parse Server, is still maintained: version 9.10.5 shipped on October 16, 2026.","Progress bought Kinvey in 2017 and retired Telerik Platform on May 10, 2018. As of October 17, 2026, kinvey.com has no website and progress.com/kinvey ends in a 404.","MongoDB removed Atlas Device Sync and the Realm-based Device SDKs on September 30, 2025. The on-device database lives on as open source, without sync.","For a new app in 2026, the realistic choices are Firebase, Supabase, Parse Server (self-hosted or on Back4App), Appwrite and PocketBase.","Pick the one you could leave. An open-source backend you can self-host protects you from the next shutdown.","https://app369.com/blog/parse-kinvey-backend-as-a-service-alternatives-2026/","pScspKFFx6bIN00EzeLsry6YCZpULCvf8ImgZyrkMV4",{"id":1188,"title":1189,"author":1190,"body":1192,"category":603,"createdAt":604,"description":1886,"disclosure":606,"extension":607,"faq":1887,"howTo":606,"location":624,"meta":1903,"navigation":631,"ogImage":606,"path":1909,"primaryKeyword":1910,"readingTime":1143,"related":1911,"seo":1913,"sources":1914,"stem":1958,"tags":1959,"takeaways":1960,"updatedAt":604,"url":1966,"__hash__":1967},"blog/blog/firebase-dynamic-links-shutdown-deep-linking-2026.md","Deep Linking in 2026: What Replaced Firebase Dynamic Links and How to Set It Up",{"name":7,"social":1191},{"twitter":9},{"type":11,"value":1193,"toc":1877},[1194,1200,1203,1207,1247,1250,1254,1257,1278,1281,1298,1301,1305,1431,1434,1436,1471,1474,1478,1481,1510,1612,1637,1713,1716,1790,1793,1797,1824,1827,1853,1856,1858,1860,1873],[14,1195,1196,1199],{},[17,1197,1198],{},"A deep link is a link that opens a specific screen inside a mobile app, not just the app's front door. Firebase Dynamic Links, the free Google service many apps used for this, shut down on August 25, 2025."," In 2026 you have two real choices. Use Universal Links and Android App Links on your own domain for free, or pay a provider such as Branch, AppsFlyer, Adjust or Airbridge if you need links that survive an app install.",[14,1201,1202],{},"This guide replaces the older deep linking explainers and vendor docs that no longer load. Every date and price below comes from the vendor's own page, checked on October 17, 2026.",[25,1204,1206],{"id":1205},"what-deep-linking-means-in-plain-words","What deep linking means, in plain words",[575,1208,1209,1215,1225,1235,1241],{},[425,1210,1211,1214],{},[17,1212,1213],{},"Deep link."," A link that goes to a place inside an app, such as a product, an invoice or an invite. A normal link opens the app's home screen at best.",[425,1216,1217,1220,1221,1224],{},[17,1218,1219],{},"Universal Links (iOS)."," Apple's version. You tap a normal https link, and iOS opens your app if it is installed. If not, the link opens in the browser. Apple checks a file on your website, called ",[480,1222,1223],{},"apple-app-site-association",", to confirm the link belongs to your app.",[425,1226,1227,1230,1231,1234],{},[17,1228,1229],{},"Android App Links."," Google's version. Same idea. Android checks a file called ",[480,1232,1233],{},"assetlinks.json"," on your website.",[425,1236,1237,1240],{},[17,1238,1239],{},"Deferred deep link."," A link that works even when the app is not installed yet. The user taps, installs the app from the store, and lands on the right screen on first open. This is what Dynamic Links did well, and it is the part plain Universal Links and App Links do not do.",[425,1242,1243,1246],{},[17,1244,1245],{},"Click analytics."," Counts of who clicked which link. Dynamic Links had some. Google's migration guide offers no replacement for it.",[14,1248,1249],{},"Marketers mostly care about the last two. Developers mostly care about the first three.",[25,1251,1253],{"id":1252},"what-happened-to-firebase-dynamic-links","What happened to Firebase Dynamic Links",[14,1255,1256],{},"Google's own FAQ says Dynamic Links shut down on August 25, 2025. This is what that means for old links:",[575,1258,1259,1262,1265,1272,1275],{},[425,1260,1261],{},"Every clicked link returns an HTTP 404 to the user.",[425,1263,1264],{},"Short link creation and link stats API calls return 400 or 403 errors.",[425,1266,1267,1268,1271],{},"Existing ",[480,1269,1270],{},".page.link"," domains cannot be kept or transferred. Domain and link data is marked for deletion on the shutdown date.",[425,1273,1274],{},"The SDKs will not crash your app by themselves, but your code has to handle the new responses. For example, on iOS, short link creation now returns a 403, and first-open attribution returns empty data.",[425,1276,1277],{},"Email link sign-in, password reset and email verification on mobile needed updated SDKs. Google has separate guides for iOS and Android.",[14,1279,1280],{},"Google's own advice, in its FAQ:",[422,1282,1283,1286,1289,1292],{},[425,1284,1285],{},"If you need full feature parity, use a third-party provider. The FAQ names Adjust, Airbridge, AppsFlyer, Bitly, Branch, Kochava and Singular, and says Google has not vetted them.",[425,1287,1288],{},"If you only need to open an installed app, use Universal Links and App Links. The official migration guide covers this path.",[425,1290,1291],{},"If you no longer need the links, review them, delete the URL prefixes and remove the SDK.",[425,1293,1294,1295,554],{},"Export your link metadata, and if you keep a custom domain, update your rewrite rules in ",[480,1296,1297],{},"firebase.json",[14,1299,1300],{},"The migration guide is honest about the gap. Universal Links and App Links do not send users to the app store, and do not carry the journey through a first install. For iOS it recommends Smart App Banners as the closest substitute.",[25,1302,1304],{"id":1303},"what-to-use-now","What to use now",[30,1306,1307,1322],{},[33,1308,1309],{},[36,1310,1311,1313,1316,1319],{},[39,1312,212],{},[39,1314,1315],{},"Deferred deep linking",[39,1317,1318],{},"Click analytics",[39,1320,1321],{},"Price (checked October 17, 2026)",[52,1323,1324,1338,1358,1378,1397,1416],{},[36,1325,1326,1331,1333,1335],{},[57,1327,1328],{},[17,1329,1330],{},"Universal Links + App Links on your own domain",[57,1332,905],{},[57,1334,905],{},[57,1336,1337],{},"Free. You pay for your domain and hosting.",[36,1339,1340,1345,1348,1350],{},[57,1341,1342],{},[17,1343,1344],{},"Branch",[57,1346,1347],{},"Yes",[57,1349,1347],{},[57,1351,1352,1353],{},"Basics plan: free trial, no price shown. Essentials and Enterprise: \"Request a demo.\" See ",[72,1354,1357],{"href":1355,"rel":1356},"https://www.branch.io/pricing/",[76],"branch.io/pricing",[36,1359,1360,1365,1368,1370],{},[57,1361,1362],{},[17,1363,1364],{},"AppsFlyer (OneLink)",[57,1366,1367],{},"Yes, from the Standard plan (Zero is free but has no deferred linking)",[57,1369,1347],{},[57,1371,1372,1373],{},"Deep Linking plans: Zero is labelled \"Free.\" Standard, Advanced and Premium show \"Custom pricing\" with \"Request a demo.\" See ",[72,1374,1377],{"href":1375,"rel":1376},"https://www.appsflyer.com/pricing/deep-linking",[76],"appsflyer.com/pricing/deep-linking",[36,1379,1380,1385,1387,1389],{},[57,1381,1382],{},[17,1383,1384],{},"Adjust",[57,1386,1347],{},[57,1388,1347],{},[57,1390,390,1391,1396],{},[72,1392,1395],{"href":1393,"rel":1394},"https://www.adjust.com/pricing/",[76],"adjust.com/pricing",". Its pricing page would not load for us on October 17, so we are not quoting a number.",[36,1398,1399,1404,1406,1408],{},[57,1400,1401],{},[17,1402,1403],{},"Airbridge",[57,1405,1347],{},[57,1407,1347],{},[57,1409,1410,1411],{},"Core plan: $40+ a month after a 30-day free trial, deep linking included. Growth plan: custom. See ",[72,1412,1415],{"href":1413,"rel":1414},"https://www.airbridge.io/pricing",[76],"airbridge.io/pricing",[36,1417,1418,1423,1426,1428],{},[57,1419,1420],{},[17,1421,1422],{},"Bitly, Kochava, Singular",[57,1424,1425],{},"Check each vendor",[57,1427,1425],{},[57,1429,1430],{},"Named in Google's FAQ. Prices not checked here, so see each vendor's pricing page.",[14,1432,1433],{},"Two cautions on that table. First, \"deferred\" and \"analytics\" here are what these vendors sell in general. Test the exact features on the plan you are quoted. Second, several of these tools are attribution platforms first and link tools second. If you only need links, that can be a lot of product to buy.",[25,1435,420],{"id":419},[422,1437,1438,1444,1450,1456,1462],{},[425,1439,1440,1443],{},[17,1441,1442],{},"Your users already have the app, and links come from emails, your website or in-app shares."," Use plain Universal Links and App Links. It is free, it is the platform's own mechanism, and no vendor can shut it down.",[425,1445,1446,1449],{},[17,1447,1448],{},"You run paid ads that send new users to the app store."," You need deferred deep linking and attribution. Pick a provider, and ask for a quote that matches your install volume.",[425,1451,1452,1455],{},[17,1453,1454],{},"You are a small team that wants links and little else."," Look at the lowest published tier first (Airbridge Core or AppsFlyer Zero; Zero covers basic routing only), and read what the free or entry plan actually excludes before you commit.",[425,1457,1458,1461],{},[17,1459,1460],{},"You want first-open routing without a vendor."," Combine Universal Links, a Smart App Banner on iOS, and a small server route that remembers the intended screen. It takes some build time, but you own it.",[425,1463,1464,1467,1468,1470],{},[17,1465,1466],{},"You have old Dynamic Links printed or published."," Links on a ",[480,1469,1270],{}," domain are gone for good, because Google will not let anyone keep those domains. If your links used your own custom domain, point that domain at your website and redirect the old paths to the right pages. Either way, publish new links on your own domain.",[14,1472,1473],{},"If you are unsure, start with option 1. You can add a provider later without changing your domain files.",[25,1475,1477],{"id":1476},"set-up-universal-links-and-app-links-on-your-own-domain","Set up Universal Links and App Links on your own domain",[14,1479,1480],{},"Use a domain you control, and use the same domain in every step. Apple and Google both want the files served over HTTPS with no redirects.",[422,1482,1483,1496],{},[425,1484,1485,1488,1489,543,1492,1495],{},[17,1486,1487],{},"Pick the links."," Decide which paths open the app, for example ",[480,1490,1491],{},"/invite/*",[480,1493,1494],{},"/invoice/*",". Keep the list short.",[425,1497,1498,1501,1502,1505,1506,1509],{},[17,1499,1500],{},"Create the iOS file."," Host it at ",[480,1503,1504],{},"https://yourdomain.com/.well-known/apple-app-site-association",". The name has no ",[480,1507,1508],{},".json"," extension. Apple's docs say to host it over HTTPS with a valid certificate and no redirects. A minimal version looks like this:",[1511,1512,1516],"pre",{"className":1513,"code":1514,"language":1515,"meta":594,"style":594},"language-json shiki shiki-themes github-light github-dark","{\n  \"applinks\": {\n    \"details\": [\n      {\n        \"appIDs\": [\"TEAMID.com.example.app\"],\n        \"components\": [{ \"/\": \"/invite/*\" }]\n      }\n    ]\n  }\n}\n","json",[480,1517,1518,1527,1536,1545,1551,1567,1588,1594,1600,1606],{"__ignoreMap":594},[1519,1520,1523],"span",{"class":1521,"line":1522},"line",1,[1519,1524,1526],{"class":1525},"sVt8B","{\n",[1519,1528,1529,1533],{"class":1521,"line":595},[1519,1530,1532],{"class":1531},"sj4cs","  \"applinks\"",[1519,1534,1535],{"class":1525},": {\n",[1519,1537,1539,1542],{"class":1521,"line":1538},3,[1519,1540,1541],{"class":1531},"    \"details\"",[1519,1543,1544],{"class":1525},": [\n",[1519,1546,1548],{"class":1521,"line":1547},4,[1519,1549,1550],{"class":1525},"      {\n",[1519,1552,1554,1557,1560,1564],{"class":1521,"line":1553},5,[1519,1555,1556],{"class":1531},"        \"appIDs\"",[1519,1558,1559],{"class":1525},": [",[1519,1561,1563],{"class":1562},"sZZnC","\"TEAMID.com.example.app\"",[1519,1565,1566],{"class":1525},"],\n",[1519,1568,1570,1573,1576,1579,1582,1585],{"class":1521,"line":1569},6,[1519,1571,1572],{"class":1531},"        \"components\"",[1519,1574,1575],{"class":1525},": [{ ",[1519,1577,1578],{"class":1531},"\"/\"",[1519,1580,1581],{"class":1525},": ",[1519,1583,1584],{"class":1562},"\"/invite/*\"",[1519,1586,1587],{"class":1525}," }]\n",[1519,1589,1591],{"class":1521,"line":1590},7,[1519,1592,1593],{"class":1525},"      }\n",[1519,1595,1597],{"class":1521,"line":1596},8,[1519,1598,1599],{"class":1525},"    ]\n",[1519,1601,1603],{"class":1521,"line":1602},9,[1519,1604,1605],{"class":1525},"  }\n",[1519,1607,1609],{"class":1521,"line":1608},10,[1519,1610,1611],{"class":1525},"}\n",[422,1613,1614,1624],{"start":1538},[425,1615,1616,1619,1620,1623],{},[17,1617,1618],{},"Add the iOS entitlement."," In Xcode, open Signing & Capabilities, add Associated Domains, and add ",[480,1621,1622],{},"applinks:yourdomain.com",". Use the bare domain, with no path and no trailing slash. Personal development teams cannot use this capability (per Flutter's setup guide).",[425,1625,1626,1501,1629,1632,1633,1636],{},[17,1627,1628],{},"Create the Android file.",[480,1630,1631],{},"https://yourdomain.com/.well-known/assetlinks.json",", with content type ",[480,1634,1635],{},"application/json"," and no redirects:",[1511,1638,1640],{"className":1513,"code":1639,"language":1515,"meta":594,"style":594},"[{\n  \"relation\": [\"delegate_permission/common.handle_all_urls\"],\n  \"target\": {\n    \"namespace\": \"android_app\",\n    \"package_name\": \"com.example.app\",\n    \"sha256_cert_fingerprints\": [\"AA:BB:...:FF\"]\n  }\n}]\n",[480,1641,1642,1647,1659,1666,1679,1691,1704,1708],{"__ignoreMap":594},[1519,1643,1644],{"class":1521,"line":1522},[1519,1645,1646],{"class":1525},"[{\n",[1519,1648,1649,1652,1654,1657],{"class":1521,"line":595},[1519,1650,1651],{"class":1531},"  \"relation\"",[1519,1653,1559],{"class":1525},[1519,1655,1656],{"class":1562},"\"delegate_permission/common.handle_all_urls\"",[1519,1658,1566],{"class":1525},[1519,1660,1661,1664],{"class":1521,"line":1538},[1519,1662,1663],{"class":1531},"  \"target\"",[1519,1665,1535],{"class":1525},[1519,1667,1668,1671,1673,1676],{"class":1521,"line":1547},[1519,1669,1670],{"class":1531},"    \"namespace\"",[1519,1672,1581],{"class":1525},[1519,1674,1675],{"class":1562},"\"android_app\"",[1519,1677,1678],{"class":1525},",\n",[1519,1680,1681,1684,1686,1689],{"class":1521,"line":1553},[1519,1682,1683],{"class":1531},"    \"package_name\"",[1519,1685,1581],{"class":1525},[1519,1687,1688],{"class":1562},"\"com.example.app\"",[1519,1690,1678],{"class":1525},[1519,1692,1693,1696,1698,1701],{"class":1521,"line":1569},[1519,1694,1695],{"class":1531},"    \"sha256_cert_fingerprints\"",[1519,1697,1559],{"class":1525},[1519,1699,1700],{"class":1562},"\"AA:BB:...:FF\"",[1519,1702,1703],{"class":1525},"]\n",[1519,1705,1706],{"class":1521,"line":1590},[1519,1707,1605],{"class":1525},[1519,1709,1710],{"class":1521,"line":1596},[1519,1711,1712],{"class":1525},"}]\n",[14,1714,1715],{},"If you use Google Play App Signing, copy the fingerprint from the Play Console (Release, Setup, App signing). The one from your local keystore will usually not match what is on users' phones.",[422,1717,1718,1750,1756],{"start":1553},[425,1719,1720,1723,1724,1727,1728,1731,1732,1735,1736,1739,1740,525,1743,1746,1747,554],{},[17,1721,1722],{},"Add the Android intent filter."," In ",[480,1725,1726],{},"AndroidManifest.xml",", add an ",[480,1729,1730],{},"intent-filter"," with ",[480,1733,1734],{},"android:autoVerify=\"true\"",", the ",[480,1737,1738],{},"VIEW"," action, the ",[480,1741,1742],{},"DEFAULT",[480,1744,1745],{},"BROWSABLE"," categories, and ",[480,1748,1749],{},"\u003Cdata android:scheme=\"https\" android:host=\"yourdomain.com\" />",[425,1751,1752,1755],{},[17,1753,1754],{},"Handle the link in your app."," Read the incoming URL and route to the right screen. Do this for both a cold start and an app that is already running.",[425,1757,1758,1761],{},[17,1759,1760],{},"Test before you ship.",[575,1762,1763,1770,1787],{},[425,1764,1765,1766,1769],{},"iOS: Apple fetches your file through its own CDN. Per Apple's docs, the CDN asks for your file within 24 hours, and devices re-check about once a week. You can see what Apple has cached at ",[480,1767,1768],{},"https://app-site-association.cdn-apple.com/a/v1/yourdomain.com",". For a private dev server, Apple's alternate mode bypasses the CDN. Then tap a link from the Notes app on a real device.",[425,1771,1772,1773,1776,1777,1780,1781,1786],{},"Android: run ",[480,1774,1775],{},"adb shell pm get-app-links com.example.app"," and look for ",[480,1778,1779],{},"verified"," next to your domain. Google's ",[72,1782,1785],{"href":1783,"rel":1784},"https://developers.google.com/digital-asset-links/tools/generator",[76],"Statement List Generator and Tester"," can generate and check the file.",[425,1788,1789],{},"We know of no Apple-run web validator for the apple-app-site-association file today, so on iOS rely on the CDN URL above and a real device.",[14,1791,1792],{},"The usual failures are a redirect in front of the file (including www to non-www), the wrong signing fingerprint, a Team ID typo, and testing before Apple's CDN has caught up.",[25,1794,1796],{"id":1795},"flutter-specifics","Flutter specifics",[14,1798,1799,1800,525,1805,1810,1811,1814,1815,525,1818,1821,1822,554],{},"Flutter has official guides for both platforms: ",[72,1801,1804],{"href":1802,"rel":1803},"https://docs.flutter.dev/cookbook/navigation/set-up-universal-links",[76],"set up universal links",[72,1806,1809],{"href":1807,"rel":1808},"https://docs.flutter.dev/cookbook/navigation/set-up-app-links",[76],"set up app links",". Per those pages, Flutter 3.27 and later turn deep linking on by default. Older versions need ",[480,1812,1813],{},"FlutterDeepLinkingEnabled"," set to YES in ",[480,1816,1817],{},"Info.plist",[480,1819,1820],{},"flutter_deeplinking_enabled"," set to true in ",[480,1823,1726],{},[14,1825,1826],{},"Two ways to receive links:",[575,1828,1829,1839],{},[425,1830,1831,1834,1835,1838],{},[17,1832,1833],{},"go_router."," Flutter's built-in handling feeds incoming links to the ",[480,1836,1837],{},"Router",". go_router (version 18.1.0 on pub.dev today) is a declarative router built on that system and lists deep linking as a feature. Define your paths as routes, and an incoming link lands on the matching screen.",[425,1840,1841,1844,1845,1848,1849,1852],{},[17,1842,1843],{},"app_links."," The ",[480,1846,1847],{},"app_links"," package (7.2.2 today) handles Android App Links, iOS Universal Links and custom schemes. You subscribe to ",[480,1850,1851],{},"AppLinks().uriLinkStream",", which delivers both the first link and later ones. Per Flutter's docs, if you use a plugin like this, set the deep linking flag to false so Flutter's own handler does not conflict.",[14,1854,1855],{},"Flutter DevTools also has a Deep Links validator. It checks website configuration and manifest files, and works for Android and iOS from Flutter 3.27.",[25,1857,570],{"id":569},[14,1859,573],{},[575,1861,1862,1868],{},[425,1863,1864,1865,1867],{},"Links open the wrong screen, or the app never opens from a link: the ",[72,1866,583],{"href":582}," diagnoses one issue for $450 and fixes it for $1,200, both fixed price (the $450 is credited toward the fix).",[425,1869,1870,1871,1108],{},"Connecting a link provider, your backend and a CRM or Stripe: ",[72,1872,1107],{"href":1106},[1874,1875,1876],"style",{},"html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":594,"searchDepth":595,"depth":595,"links":1878},[1879,1880,1881,1882,1883,1884,1885],{"id":1205,"depth":595,"text":1206},{"id":1252,"depth":595,"text":1253},{"id":1303,"depth":595,"text":1304},{"id":419,"depth":595,"text":420},{"id":1476,"depth":595,"text":1477},{"id":1795,"depth":595,"text":1796},{"id":569,"depth":595,"text":570},"What deep linking is, what happened when Firebase Dynamic Links shut down on August 25, 2025, and how to set up Universal Links and Android App Links in 2026. Vendor options and prices checked October 17, 2026.",[1888,1891,1894,1897,1900],{"question":1889,"answer":1890},"When did Firebase Dynamic Links shut down?","On August 25, 2025. Google says all clicked links return an HTTP 404, short link and link stats API calls return 400 or 403 errors, and existing .page.link domains cannot be kept or transferred.",{"question":1892,"answer":1893},"What replaced Firebase Dynamic Links?","Nothing from Google replaced it one for one. Google tells developers to use Universal Links and Android App Links for links that open an installed app, and a third-party deep linking provider for full feature parity. Google names Adjust, Airbridge, AppsFlyer, Bitly, Branch, Kochava and Singular, and says it has not vetted them.",{"question":1895,"answer":1896},"What is a deferred deep link?","A link that still works when the app is not installed yet. The user taps, goes to the app store, installs the app, and lands on the right screen on first open. Universal Links and App Links cannot do this on their own. You need a provider or your own server logic.",{"question":1898,"answer":1899},"Do I need a paid service for deep links?","Not if your users already have the app. Universal Links and App Links cost nothing beyond a domain you own. You need a provider only for deferred deep linking, click analytics, or campaign attribution.",{"question":1901,"answer":1902},"How do I test Universal Links and App Links?","On iOS, check the file through Apple's CDN and tap a link from the Notes app. On Android, use adb pm get-app-links to see whether your domain shows as verified, and Google's Statement List Generator and Tester to check assetlinks.json. For Flutter apps, DevTools has a Deep Links validator.",{"readingTimeStats":1904},{"text":1905,"minutes":1906,"time":1907,"words":1908},"8 min read",7.7,462000,1540,"/blog/firebase-dynamic-links-shutdown-deep-linking-2026","firebase dynamic links alternative",[1912,1146,638],"mobile-app-analytics-tracking-guide-2026",{"title":1189,"description":1886},[1915,1917,1920,1923,1926,1929,1932,1934,1937,1939,1941,1944,1947,1950,1952,1954,1956],{"title":1916,"url":858},"Firebase Dynamic Links FAQ (shutdown date, link behaviour, recommended alternatives)",{"title":1918,"url":1919},"Firebase, Migrate to App Links and Universal Links (official migration guide)","https://firebase.google.com/support/guides/app-links-universal-links",{"title":1921,"url":1922},"Apple, Supporting associated domains","https://developer.apple.com/documentation/xcode/supporting-associated-domains",{"title":1924,"url":1925},"Apple CDN copy of an apple-app-site-association file (example: www.apple.com)","https://app-site-association.cdn-apple.com/a/v1/www.apple.com",{"title":1927,"url":1928},"Android, Verify Android App Links","https://developer.android.com/training/app-links/verify-android-applinks",{"title":1930,"url":1931},"Android, Configure website associations (assetlinks.json requirements)","https://developer.android.com/training/app-links/configure-assetlinks",{"title":1933,"url":1783},"Google, Statement List Generator and Tester",{"title":1935,"url":1936},"Flutter, Deep linking","https://docs.flutter.dev/ui/navigation/deep-linking",{"title":1938,"url":1802},"Flutter, Set up universal links (iOS)",{"title":1940,"url":1807},"Flutter, Set up app links (Android)",{"title":1942,"url":1943},"Flutter DevTools, Validate deep links","https://docs.flutter.dev/tools/devtools/deep-links",{"title":1945,"url":1946},"app_links package on pub.dev","https://pub.dev/packages/app_links",{"title":1948,"url":1949},"go_router package on pub.dev","https://pub.dev/packages/go_router",{"title":1951,"url":1355},"Branch pricing",{"title":1953,"url":1375},"AppsFlyer deep linking pricing",{"title":1955,"url":1393},"Adjust pricing",{"title":1957,"url":1413},"Airbridge pricing","blog/firebase-dynamic-links-shutdown-deep-linking-2026","firebase dynamic links alternative, deep linking, deferred deep linking, universal links, android app links, apple-app-site-association, assetlinks.json, branch alternatives, appsflyer onelink, flutter deep linking, mobile deep linking",[1961,1962,1963,1964,1965],"Firebase Dynamic Links shut down on August 25, 2025. Clicked links now return an HTTP 404, and Google says the .page.link domains cannot be kept or transferred.","Google names two routes. Use Universal Links and Android App Links if you only need links to open an installed app. Use a third-party provider if you need full feature parity.","Universal Links and App Links are free and live on your own domain. They do not do deferred deep linking, and they do not give you click analytics.","Two files make it work: /.well-known/apple-app-site-association on iOS and /.well-known/assetlinks.json on Android. Serve both over HTTPS with no redirects.","Pricing as of October 17, 2026: Airbridge Core is $40+ a month, AppsFlyer has a free Zero plan, Branch and the paid AppsFlyer plans are sales-led, and Adjust lists no price we could read.","https://app369.com/blog/firebase-dynamic-links-shutdown-deep-linking-2026/","kWZsntPKkyZ0cbGNktuWgqusyXrXGdyedktgEIg6sDo",{"id":1969,"title":1970,"author":1971,"body":1973,"category":603,"createdAt":2364,"description":2365,"disclosure":606,"extension":607,"faq":606,"howTo":606,"location":624,"meta":2366,"navigation":631,"ogImage":606,"path":2371,"primaryKeyword":606,"readingTime":1143,"related":606,"seo":2372,"sources":606,"stem":2373,"tags":2374,"takeaways":606,"updatedAt":2364,"url":2375,"__hash__":2376},"blog/blog/how-to-debug-a-flutter-firebase-bug-2026.md","How to Debug a Flutter and Firebase Bug: Find the Root Cause (2026)",{"name":7,"social":1972},{"twitter":9},{"type":11,"value":1974,"toc":2343},[1975,1981,1989,1993,1996,2010,2013,2017,2020,2104,2113,2117,2125,2129,2134,2171,2175,2178,2193,2197,2223,2227,2251,2255,2262,2266,2274,2278,2290,2294,2298,2306,2310,2316,2320,2329,2333,2336,2340],[14,1976,1977,1980],{},[17,1978,1979],{},"Most Flutter and Firebase bugs that take days to fix take days to find, not to fix."," Once you can reproduce the bug on demand and you know which layer it lives in (the app, Firebase's servers, or the build tooling), the fix is usually small. This guide is the order to work in, then the five problems that come up most.",[14,1982,1983,1984,1988],{},"It is the method behind App369's ",[72,1985,1987],{"href":1986},"/fixed-price/#fix-ticket","fixed-price Flutter & Firebase Fix Ticket",", and the one Simon uses on his own production Flutter and Firebase SaaS, Workspace369.",[25,1990,1992],{"id":1991},"step-1-write-down-exact-reproduction-steps","Step 1: Write down exact reproduction steps",[14,1994,1995],{},"Before reading any code, write the bug as steps someone else could follow:",[422,1997,1998,2001,2004,2007],{},[425,1999,2000],{},"Which build: the app version, build number, and whether it is debug, profile or release.",[425,2002,2003],{},"Which device and OS version, and whether it happens on web, iOS, Android or all three.",[425,2005,2006],{},"Which account or data: a new user, an existing user, a specific record.",[425,2008,2009],{},"The exact taps, and what you expected versus what happened.",[14,2011,2012],{},"If it only happens \"sometimes\", note what the failing cases have in common: a slow network, a large account, the app coming back from the background. A bug you can't reproduce can't be verified as fixed.",[25,2014,2016],{"id":2015},"step-2-find-out-which-layer-is-failing","Step 2: Find out which layer is failing",[14,2018,2019],{},"Each layer has its own log, and the error is usually already in one of them:",[30,2021,2022,2032],{},[33,2023,2024],{},[36,2025,2026,2029],{},[39,2027,2028],{},"Layer",[39,2030,2031],{},"Where to look",[52,2033,2034,2052,2064,2075,2089],{},[36,2035,2036,2039],{},[57,2037,2038],{},"Flutter app",[57,2040,2041,2042,2045,2046,2051],{},"The ",[480,2043,2044],{},"flutter run"," console, and ",[72,2047,2050],{"href":2048,"rel":2049},"https://docs.flutter.dev/tools/devtools",[76],"Flutter DevTools"," for widgets, network and memory",[36,2053,2054,2057],{},[57,2055,2056],{},"Release builds in users' hands",[57,2058,2059,2063],{},[72,2060,351],{"href":2061,"rel":2062},"https://firebase.google.com/docs/crashlytics",[76]," for crashes and non-fatal errors you record",[36,2065,2066,2069],{},[57,2067,2068],{},"Cloud Functions",[57,2070,2071,2072],{},"Logs Explorer in the Google Cloud console, or ",[480,2073,2074],{},"firebase functions:log",[36,2076,2077,2080],{},[57,2078,2079],{},"Firestore and Storage",[57,2081,2082,2083,543,2086],{},"The exact error code your app receives, such as ",[480,2084,2085],{},"permission-denied",[480,2087,2088],{},"failed-precondition",[36,2090,2091,2094],{},[57,2092,2093],{},"Build tooling",[57,2095,2096,2097,1731,2100,2103],{},"The full output of ",[480,2098,2099],{},"flutter build",[480,2101,2102],{},"-v",", plus Xcode or Gradle's own logs",[14,2105,2106,2107,2109,2110,2112],{},"A Firestore ",[480,2108,2085],{}," error means Security Rules refused the request; it is not an app crash. A ",[480,2111,2088],{}," error on a query often includes a link to create the missing index. Read the full message before changing code.",[25,2114,2116],{"id":2115},"step-3-isolate-it-with-the-emulator-suite","Step 3: Isolate it with the Emulator Suite",[14,2118,2041,2119,2124],{},[72,2120,2123],{"href":2121,"rel":2122},"https://firebase.google.com/docs/emulator-suite",[76],"Firebase Local Emulator Suite"," runs Auth, Firestore, Functions and Storage on your machine. Point a debug build at the emulators, load the data that triggers the bug, and you can repeat the failing steps as often as you need without touching production data. Security Rules problems in particular are easier to see in the emulator UI, which shows which rule allowed or denied each request.",[25,2126,2128],{"id":2127},"the-five-issues-that-come-up-most","The five issues that come up most",[2130,2131,2133],"h3",{"id":2132},"build-failures","Build failures",[575,2135,2136,2143,2161,2168],{},[425,2137,2138,2139,2142],{},"Run ",[480,2140,2141],{},"flutter doctor -v"," first. It catches missing toolchains, licenses and Xcode or Android SDK problems.",[425,2144,2145,2146,2149,2150,525,2153,2156,2157,2160],{},"For iOS, check the minimum iOS version in the ",[480,2147,2148],{},"Podfile"," against what your Firebase plugins require, then run ",[480,2151,2152],{},"pod repo update",[480,2154,2155],{},"pod install"," in the ",[480,2158,2159],{},"ios"," folder.",[425,2162,2163,2164,2167],{},"For Android, check that the Android Gradle Plugin, Gradle and Kotlin versions are compatible with each other, and that ",[480,2165,2166],{},"minSdkVersion"," meets your plugins' minimum.",[425,2169,2170],{},"After upgrading Flutter or the FlutterFire plugins, upgrade all FlutterFire plugins together; mixed versions are a common cause of build errors.",[2130,2172,2174],{"id":2173},"login-loops","Login loops",[14,2176,2177],{},"A user signs in and lands back on the sign-in screen, or the app flickers between screens. The usual causes:",[575,2179,2180,2187,2190],{},[425,2181,2182,2183,2186],{},"The router redirects before Firebase Auth has restored the session. On a cold start, ",[480,2184,2185],{},"authStateChanges()"," emits once the saved user is loaded; decide the first screen after that first event, not before.",[425,2188,2189],{},"Redirect logic that reads two different sources of truth, such as the auth state and a user profile document that hasn't loaded yet.",[425,2191,2192],{},"On web, the redirect sign-in flow returning to a page that immediately redirects again.",[2130,2194,2196],{"id":2195},"firestore-writes-that-hang","Firestore writes that hang",[14,2198,2199,2200,543,2203,2206,2207,2210,2211,2213,2214,2216,2217,2219,2220,2222],{},"A ",[480,2201,2202],{},"set()",[480,2204,2205],{},"update()"," call whose ",[480,2208,2209],{},"Future"," never completes is often not stuck at all. With offline persistence, which is on by default on Android and iOS, the write is applied to the local cache immediately, and the ",[480,2212,2209],{}," completes only when the server confirms it. On a poor connection or with no connection, that can take a long time. Don't block the UI on the ",[480,2215,2209],{},": let the snapshot listener show the change. If the write is rejected, the ",[480,2218,2209],{}," completes with an error such as ",[480,2221,2085],{},", so make sure something catches and reports it.",[2130,2224,2226],{"id":2225},"cloud-function-errors","Cloud Function errors",[575,2228,2229,2235,2242,2248],{},[425,2230,2231,2232,554],{},"Read the function's own logs before the client error; the client often only receives ",[480,2233,2234],{},"internal",[425,2236,2237,2238,2241],{},"In callable functions, throw an ",[480,2239,2240],{},"HttpsError"," with a clear code and message, so the app can show a useful error instead of a generic one.",[425,2243,2244,2245,554],{},"Check the function's region in the app matches where it is deployed; a callable in the wrong region returns ",[480,2246,2247],{},"not-found",[425,2249,2250],{},"For timeouts, compare the configured timeout and memory with what the function actually does.",[2130,2252,2254],{"id":2253},"a-broken-screen","A broken screen",[14,2256,2257,2258,2261],{},"A red error screen in debug, or a grey one in release, means an exception was thrown during build. The console shows the first exception; fix that one first, because later errors are often caused by it. Common causes are a ",[480,2259,2260],{},"null"," value from a document field that doesn't exist on older records, and a list or column without bounded height inside a scrolling parent.",[25,2263,2265],{"id":2264},"fix-it-with-a-test","Fix it with a test",[14,2267,2268,2269,2273],{},"When you've found the root cause, write a test that fails because of it, then make it pass. Widget tests cover screens and state; the ",[72,2270,2272],{"href":2121,"rel":2271},[76],"Firebase emulators"," let integration tests and Security Rules tests run against real Firebase behavior. The test keeps the bug from coming back in the next release.",[25,2275,2277],{"id":2276},"when-to-get-help","When to get help",[14,2279,2280,2281,2284,2285,2289],{},"If a bug has eaten more than a day, App369 offers a ",[72,2282,2283],{"href":1986},"fixed-price Fix Ticket",". The $450 Diagnosis delivers the root cause with evidence and a fixed repair quote within 3 business days, and the $450 is credited toward the fix. The $1,200 Fix delivers one scoped defect fixed as a pull request, with a regression test and handover notes, within 5 business days. If the problem turns out to be your Security Rules, the ",[72,2286,2288],{"href":2287},"/blog/firebase-security-guide-2026/","Firebase Security Rules guide"," is a good next read.",[25,2291,2293],{"id":2292},"frequently-asked-questions","Frequently Asked Questions",[2130,2295,2297],{"id":2296},"why-does-my-firestore-write-never-finish","Why does my Firestore write never finish?",[14,2299,2300,2301,2303,2304,554],{},"With offline persistence, a write is saved to the local cache at once, but its ",[480,2302,2209],{}," completes only when the server confirms it. On a slow or missing connection that can take a long time. Show the change from your snapshot listener instead of waiting on the write, and catch errors such as ",[480,2305,2085],{},[2130,2307,2309],{"id":2308},"why-does-my-flutter-app-keep-returning-to-the-login-screen","Why does my Flutter app keep returning to the login screen?",[14,2311,2312,2313,2315],{},"Usually because the router decides where to go before Firebase Auth has restored the saved session, or because redirect logic depends on data that hasn't loaded yet. Wait for the first ",[480,2314,2185],{}," event before choosing the first screen.",[2130,2317,2319],{"id":2318},"how-do-i-see-cloud-functions-errors","How do I see Cloud Functions errors?",[14,2321,2322,2323,2325,2326,2328],{},"In Logs Explorer in the Google Cloud console, or with ",[480,2324,2074],{},". The app often receives only a generic ",[480,2327,2234],{}," error, so the function's own logs are where the real message is.",[2130,2330,2332],{"id":2331},"can-i-debug-firebase-without-touching-production-data","Can I debug Firebase without touching production data?",[14,2334,2335],{},"Yes. The Firebase Local Emulator Suite runs Auth, Firestore, Functions and Storage locally. Load test data that reproduces the bug and point a debug build at the emulators.",[2130,2337,2339],{"id":2338},"what-should-i-send-a-developer-to-fix-a-flutter-bug","What should I send a developer to fix a Flutter bug?",[14,2341,2342],{},"Exact reproduction steps, the app version and build number, the device and OS, the error message or a screen recording, and access to the repository. With those, a developer can usually reproduce the bug on the first try.",{"title":594,"searchDepth":595,"depth":595,"links":2344},[2345,2346,2347,2348,2355,2356,2357],{"id":1991,"depth":595,"text":1992},{"id":2015,"depth":595,"text":2016},{"id":2115,"depth":595,"text":2116},{"id":2127,"depth":595,"text":2128,"children":2349},[2350,2351,2352,2353,2354],{"id":2132,"depth":1538,"text":2133},{"id":2173,"depth":1538,"text":2174},{"id":2195,"depth":1538,"text":2196},{"id":2225,"depth":1538,"text":2226},{"id":2253,"depth":1538,"text":2254},{"id":2264,"depth":595,"text":2265},{"id":2276,"depth":595,"text":2277},{"id":2292,"depth":595,"text":2293,"children":2358},[2359,2360,2361,2362,2363],{"id":2296,"depth":1538,"text":2297},{"id":2308,"depth":1538,"text":2309},{"id":2318,"depth":1538,"text":2319},{"id":2331,"depth":1538,"text":2332},{"id":2338,"depth":1538,"text":2339},"2026-10-12T15:00:00.000Z","Find the root cause of a Flutter and Firebase bug: reproduce it, read the right logs, isolate it with the Emulator Suite, and fix the five most common issues.",{"readingTimeStats":2367},{"text":627,"minutes":2368,"time":2369,"words":2370},5.665,339900,1133,"/blog/how-to-debug-a-flutter-firebase-bug-2026",{"title":1970,"description":2365},"blog/how-to-debug-a-flutter-firebase-bug-2026","flutter debugging, firebase debugging, flutter build failure, firebase auth, firestore, cloud functions errors","https://app369.com/blog/how-to-debug-a-flutter-firebase-bug-2026/","Og5eeAe_Qd9f0SuWjNTINlCluQrpEjwYZ_XH4tsTFRU",{"id":2378,"title":2379,"author":2380,"body":2382,"category":603,"createdAt":2873,"description":2874,"disclosure":606,"extension":607,"faq":606,"howTo":606,"location":624,"meta":2875,"navigation":631,"ogImage":606,"path":2880,"primaryKeyword":606,"readingTime":2881,"related":606,"seo":2882,"sources":606,"stem":2883,"tags":2884,"takeaways":606,"updatedAt":2873,"url":2885,"__hash__":2886},"blog/blog/flutter-ios-build-failed-after-upgrade-2026.md","Flutter iOS Build Failed After an Upgrade? Fix CocoaPods and Xcode Errors (2026)",{"name":7,"social":2381},{"twitter":9},{"type":11,"value":2383,"toc":2856},[2384,2390,2400,2404,2407,2439,2442,2498,2502,2532,2536,2545,2570,2574,2579,2623,2697,2714,2718,2730,2762,2766,2775,2778,2782,2785,2787,2793,2795,2799,2813,2817,2829,2833,2836,2840,2846,2850,2853],[14,2385,2386,2389],{},[17,2387,2388],{},"When a Flutter iOS build breaks right after an upgrade, the cause is almost always one of four things: a stale CocoaPods lock, a deployment target that is too low, FlutterFire plugins on mismatched versions, or an Xcode that no longer matches the SDKs you depend on."," The error Xcode shows first is rarely the real one. This guide is the order to work in, from reading the actual failure to the fixes that cover most upgrade breakages.",[14,2391,2392,2393,2395,2396,554],{},"It is the same approach Simon uses on Workspace369, his production Flutter and Firebase SaaS, and it is the iOS build part of App369's ",[72,2394,1987],{"href":582},". For the wider method, see ",[72,2397,2399],{"href":2398},"/blog/how-to-debug-a-flutter-firebase-bug-2026/","how to debug a Flutter and Firebase bug",[25,2401,2403],{"id":2402},"step-1-read-the-real-error","Step 1: Read the real error",[14,2405,2406],{},"Don't start by deleting folders. First get the full output.",[422,2408,2409,2414,2428],{},[425,2410,2138,2411,2413],{},[480,2412,2141],{}," and fix anything it flags under Xcode or CocoaPods.",[425,2415,2138,2416,2419,2420,2423,2424,2427],{},[480,2417,2418],{},"flutter build ios -v"," (or ",[480,2421,2422],{},"flutter run -v",") and read from the first line that says ",[480,2425,2426],{},"error:",", not the last line. The final \"Xcode build failed\" message is a summary.",[425,2429,2430,2431,2434,2435,2438],{},"If the failure happens in Xcode itself, open ",[480,2432,2433],{},"ios/Runner.xcworkspace"," (never ",[480,2436,2437],{},"Runner.xcodeproj",") and use the Report navigator to open the build log. Filter for errors and read the first one.",[14,2440,2441],{},"Where the error appears tells you which step failed:",[30,2443,2444,2454],{},[33,2445,2446],{},[36,2447,2448,2451],{},[39,2449,2450],{},"Where it fails",[39,2452,2453],{},"Likely area",[52,2455,2456,2466,2474,2482,2490],{},[36,2457,2458,2463],{},[57,2459,2460,2462],{},[480,2461,2155],{}," output, before compiling",[57,2464,2465],{},"CocoaPods resolution, Podfile, specs",[36,2467,2468,2471],{},[57,2469,2470],{},"\"Compiling for iOS X, but module requires iOS Y\"",[57,2472,2473],{},"Deployment target too low",[36,2475,2476,2479],{},[57,2477,2478],{},"Swift or Objective-C compile errors inside a plugin",[57,2480,2481],{},"Plugin and Xcode or SDK version mismatch",[36,2483,2484,2487],{},[57,2485,2486],{},"Linking or \"framework not found\"",[57,2488,2489],{},"Stale Pods or build cache",[36,2491,2492,2495],{},[57,2493,2494],{},"Code signing messages",[57,2496,2497],{},"Signing and provisioning, covered at the end",[25,2499,2501],{"id":2500},"step-2-check-your-xcode-and-cocoapods-versions","Step 2: Check your Xcode and CocoaPods versions",[14,2503,2504,2505,2510,2511,525,2514,2517,2518,2523,2524,2527,2528,2531],{},"Upgrades often fail because the Firebase SDK moved its minimum requirements. The ",[72,2506,2509],{"href":2507,"rel":2508},"https://firebase.google.com/docs/ios/installation-methods",[76],"Firebase Apple platforms installation docs"," list the current Xcode requirement and say the CocoaPods distribution needs CocoaPods 1.12.0 or higher. Check yours with ",[480,2512,2513],{},"pod --version",[480,2515,2516],{},"xcodebuild -version",", and update if either is below what your plugins need. Flutter's own ",[72,2519,2522],{"href":2520,"rel":2521},"https://docs.flutter.dev/platform-integration/ios/setup",[76],"iOS setup page"," covers pointing the command-line tools at the right Xcode (",[480,2525,2526],{},"xcode-select",") and accepting licenses (",[480,2529,2530],{},"sudo xcodebuild -license","); a second Xcode installed on the machine is a common reason a build uses the wrong toolchain.",[25,2533,2535],{"id":2534},"step-3-fix-the-ios-deployment-target","Step 3: Fix the iOS deployment target",[14,2537,2538,2539,2544],{},"A plugin upgrade can raise the minimum iOS version. The ",[72,2540,2543],{"href":2541,"rel":2542},"https://firebase.google.com/docs/flutter/setup",[76],"Firebase Flutter setup page"," lists iOS 15 or later as the Apple requirement for the FlutterFire plugins. Check three places and make them agree:",[575,2546,2547,2557,2560],{},[425,2548,2549,2552,2553,2556],{},[480,2550,2551],{},"ios/Podfile",": the line ",[480,2554,2555],{},"platform :ios, '15.0'"," (use the minimum your plugins ask for; if the line is commented out, uncomment it).",[425,2558,2559],{},"Xcode: Runner target, General tab, \"Minimum Deployments\".",[425,2561,2041,2562,2565,2566,2569],{},[480,2563,2564],{},"post_install"," block in the Podfile, if you have one that sets ",[480,2567,2568],{},"IPHONEOS_DEPLOYMENT_TARGET"," on every pod. A value there that is lower than a pod's own minimum produces the \"module requires iOS Y\" error.",[25,2571,2573],{"id":2572},"step-4-refresh-cocoapods-then-clean-it-out","Step 4: Refresh CocoaPods, then clean it out",[14,2575,2576,2577,2160],{},"Work from least to most destructive. Run these inside the ",[480,2578,2159],{},[422,2580,2581,2589,2617],{},[425,2582,2583,2588],{},[17,2584,2585],{},[480,2586,2587],{},"pod install --repo-update"," refreshes the local spec repository and then installs. It is the right first move after upgrading a plugin, because a stale local spec list can't find the new version.",[425,2590,2591,2596,2597,2600,2601,2606,2607,2609,2610,2612,2613,2616],{},[17,2592,2593],{},[480,2594,2595],{},"pod update PODNAME"," if one pod needs to move to a newer version than ",[480,2598,2599],{},"Podfile.lock"," allows. As the ",[72,2602,2605],{"href":2603,"rel":2604},"https://guides.cocoapods.org/using/pod-install-vs-update.html",[76],"CocoaPods guide"," explains, ",[480,2608,2155],{}," respects the versions in ",[480,2611,2599],{},", while ",[480,2614,2615],{},"pod update"," ignores the lock and fetches the newest version your constraints allow.",[425,2618,2619,2622],{},[17,2620,2621],{},"A clean reinstall."," If it is still broken, remove the generated pieces and rebuild them:",[1511,2624,2628],{"className":2625,"code":2626,"language":2627,"meta":594,"style":594},"language-bash shiki shiki-themes github-light github-dark","cd ios\nrm -rf Pods Podfile.lock\ncd ..\nflutter clean\nflutter pub get\ncd ios && pod install --repo-update\n","bash",[480,2629,2630,2638,2653,2660,2668,2678],{"__ignoreMap":594},[1519,2631,2632,2635],{"class":1521,"line":1522},[1519,2633,2634],{"class":1531},"cd",[1519,2636,2637],{"class":1562}," ios\n",[1519,2639,2640,2644,2647,2650],{"class":1521,"line":595},[1519,2641,2643],{"class":2642},"sScJk","rm",[1519,2645,2646],{"class":1531}," -rf",[1519,2648,2649],{"class":1562}," Pods",[1519,2651,2652],{"class":1562}," Podfile.lock\n",[1519,2654,2655,2657],{"class":1521,"line":1538},[1519,2656,2634],{"class":1531},[1519,2658,2659],{"class":1562}," ..\n",[1519,2661,2662,2665],{"class":1521,"line":1547},[1519,2663,2664],{"class":2642},"flutter",[1519,2666,2667],{"class":1562}," clean\n",[1519,2669,2670,2672,2675],{"class":1521,"line":1553},[1519,2671,2664],{"class":2642},[1519,2673,2674],{"class":1562}," pub",[1519,2676,2677],{"class":1562}," get\n",[1519,2679,2680,2682,2685,2688,2691,2694],{"class":1521,"line":1569},[1519,2681,2634],{"class":1531},[1519,2683,2684],{"class":1562}," ios",[1519,2686,2687],{"class":1525}," && ",[1519,2689,2690],{"class":2642},"pod",[1519,2692,2693],{"class":1562}," install",[1519,2695,2696],{"class":1531}," --repo-update\n",[14,2698,2699,2700,2703,2704,2706,2707,2709,2710,2713],{},"Deleting ",[480,2701,2702],{},"Pods"," is safe because it is generated. Deleting ",[480,2705,2599],{}," is also safe for a one-off repair, but it lets every pod re-resolve, so you may get newer versions than before. The CocoaPods guide recommends committing ",[480,2708,2599],{},", so review the diff after the reinstall and commit the new one once the build passes. If you only suspect Xcode's cache, you can also delete ",[480,2711,2712],{},"~/Library/Developer/Xcode/DerivedData","; it only holds build products, and Xcode recreates it.",[25,2715,2717],{"id":2716},"step-5-upgrade-the-flutterfire-plugins-together","Step 5: Upgrade the FlutterFire plugins together",[14,2719,2720,78,2723,78,2726,2729],{},[480,2721,2722],{},"firebase_core",[480,2724,2725],{},"cloud_firestore",[480,2727,2728],{},"firebase_auth"," and the other FlutterFire plugins are versioned together and each one depends on a specific Firebase SDK release. Upgrading one and leaving the others behind is a common source of build errors, including duplicate or conflicting native pods.",[575,2731,2732,2742,2756],{},[425,2733,2138,2734,2737,2738,2741],{},[480,2735,2736],{},"flutter pub outdated"," to see the gap, then upgrade the whole FlutterFire family in one ",[480,2739,2740],{},"pubspec.yaml"," change.",[425,2743,2744,2745,2747,2748,2752,2753,554],{},"Re-run ",[480,2746,500],{}," if you added a Firebase service or platform; the ",[72,2749,2751],{"href":2541,"rel":2750},[76],"Firebase docs"," say re-running it keeps your configuration current. Install the tool with ",[480,2754,2755],{},"dart pub global activate flutterfire_cli",[425,2757,2758,2759,2761],{},"If you pin a Firebase SDK version in the Podfile, remove the pin and let the plugins choose it. A manual pin that disagrees with ",[480,2760,2722],{}," is a classic conflict.",[25,2763,2765],{"id":2764},"step-6-know-that-cocoapods-is-being-phased-out","Step 6: Know that CocoaPods is being phased out",[14,2767,2768,2769,2774],{},"This matters for upgrades in late 2026. Firebase's docs warn that it will stop publishing new versions to CocoaPods in October 2026 and recommend Swift Package Manager. Flutter's ",[72,2770,2773],{"href":2771,"rel":2772},"https://docs.flutter.dev/packages-and-plugins/swift-package-manager/for-app-developers",[76],"Swift Package Manager page"," says SwiftPM support is on by default as of Flutter 3.44, that Flutter falls back to CocoaPods for plugins that don't support it yet, and that the CocoaPods registry becomes read-only on December 2, 2026.",[14,2776,2777],{},"In practice: after a Flutter upgrade, the first build may modify your Xcode project to add SwiftPM integration. Commit that change rather than reverting it, and if a build error mentions a Swift package, read it the same way as a pod error: find the first real failure.",[25,2779,2781],{"id":2780},"step-7-signing-errors-briefly","Step 7: Signing errors, briefly",[14,2783,2784],{},"If it compiles but fails to archive, it is usually signing. In Xcode, open the Runner target, Signing & Capabilities, and check that a team is selected, the bundle identifier matches your App Store Connect app, and \"Automatically manage signing\" is on unless you manage profiles yourself. Flutter's iOS setup page notes a signed developer certificate is needed even for device testing.",[25,2786,2277],{"id":2276},[14,2788,2789,2790,2792],{},"If an iOS build has eaten more than a day and the steps above haven't moved it, App369's ",[72,2791,1987],{"href":582}," covers build failures after a Flutter or FlutterFire upgrade. The $450 Diagnosis delivers the root cause with evidence and a fixed repair quote within 3 business days, and the $450 is credited toward the fix. The $1,200 Fix delivers the scoped defect as a pull request with a regression test within 5 business days. App Store approval isn't something anyone can guarantee; the ticket covers the code defect itself.",[25,2794,2293],{"id":2292},[2130,2796,2798],{"id":2797},"why-did-my-flutter-ios-build-fail-after-upgrading-flutter","Why did my Flutter iOS build fail after upgrading Flutter?",[14,2800,2801,2802,2804,2805,2807,2808,2810,2811,554],{},"Most often the Podfile or Xcode project still has an old iOS deployment target, ",[480,2803,2599],{}," pins old pod versions, or plugin versions no longer match each other. Run ",[480,2806,2418],{},", find the first ",[480,2809,2426],{}," line, then work through the deployment target and ",[480,2812,2587],{},[2130,2814,2816],{"id":2815},"is-it-safe-to-delete-podfilelock-and-the-pods-folder","Is it safe to delete Podfile.lock and the Pods folder?",[14,2818,2819,2820,2822,2823,2825,2826,2828],{},"Yes, for a repair. ",[480,2821,2702],{}," is generated and ",[480,2824,2599],{}," is rebuilt by ",[480,2827,2155],{},". The catch is that pods may resolve to newer versions, so check the new lock file and commit it once the build works.",[2130,2830,2832],{"id":2831},"what-does-pod-install-repo-update-do","What does \"pod install --repo-update\" do?",[14,2834,2835],{},"It refreshes CocoaPods' local list of available pod versions before installing. Use it when a newly upgraded plugin needs a pod version your machine's spec list doesn't know about yet.",[2130,2837,2839],{"id":2838},"should-i-upgrade-only-one-flutterfire-plugin","Should I upgrade only one FlutterFire plugin?",[14,2841,2842,2843,2845],{},"Avoid it. FlutterFire plugins depend on matching Firebase SDK releases, so upgrade ",[480,2844,2722],{}," and the other FlutterFire packages together and rebuild.",[2130,2847,2849],{"id":2848},"do-i-need-to-switch-from-cocoapods-to-swift-package-manager","Do I need to switch from CocoaPods to Swift Package Manager?",[14,2851,2852],{},"Flutter handles it for you in recent versions and falls back to CocoaPods for plugins that don't support SwiftPM yet. Given Firebase's announced CocoaPods change, keep your plugins current rather than pinning old versions.",[1874,2854,2855],{},"html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":594,"searchDepth":595,"depth":595,"links":2857},[2858,2859,2860,2861,2862,2863,2864,2865,2866],{"id":2402,"depth":595,"text":2403},{"id":2500,"depth":595,"text":2501},{"id":2534,"depth":595,"text":2535},{"id":2572,"depth":595,"text":2573},{"id":2716,"depth":595,"text":2717},{"id":2764,"depth":595,"text":2765},{"id":2780,"depth":595,"text":2781},{"id":2276,"depth":595,"text":2277},{"id":2292,"depth":595,"text":2293,"children":2867},[2868,2869,2870,2871,2872],{"id":2797,"depth":1538,"text":2798},{"id":2815,"depth":1538,"text":2816},{"id":2831,"depth":1538,"text":2832},{"id":2838,"depth":1538,"text":2839},{"id":2848,"depth":1538,"text":2849},"2026-10-12T18:00:00.000Z","Flutter iOS build failing after upgrading Flutter, FlutterFire or Xcode? How to read the real error, then fix CocoaPods, deployment target and plugin version mismatches.",{"readingTimeStats":2876},{"text":627,"minutes":2877,"time":2878,"words":2879},5.995,359700,1199,"/blog/flutter-ios-build-failed-after-upgrade-2026","7 min",{"title":2379,"description":2874},"blog/flutter-ios-build-failed-after-upgrade-2026","flutter ios build failed, cocoapods error, pod install failed, flutterfire upgrade, xcode build error, flutter build ios, firebase ios","https://app369.com/blog/flutter-ios-build-failed-after-upgrade-2026/","2S7ATVimG3dqa0pi1C-hx3AP4EoFgy7CwxvoeB-59DM",[2888,2890,2893,2894,2895,2896],{"keyword":5,"url":704,"title":5,"relevance":2889},86,{"keyword":2891,"url":2892,"title":2891,"relevance":1602},"Flutter vs Native in 2026: An Honest Decision Guide","https://app369.com/blog/flutter-vs-native-app-development-2026/",{"keyword":2379,"url":2885,"title":2379,"relevance":1596},{"keyword":1970,"url":2375,"title":1970,"relevance":1596},{"keyword":709,"url":1185,"title":709,"relevance":1569},{"keyword":2897,"url":2898,"title":2897,"relevance":1569},"Titanium, PhoneGap and Xamarin Are Gone: Which Cross-Platform Framework in 2026?","https://app369.com/blog/titanium-phonegap-xamarin-cross-platform-frameworks-2026/",1792228234499]