●  New: build your backend and app together with AI. Point Claude or Cursor at AppAmbit over MCP.

On mobile?

Email yourself the setup link so you can finish when you're at your computer.

iOS · Swift & Objective-C

One line at launch. Read the crash, not the addresses.

Add the SDK, call AppAmbit.start(appKey:) once, and your app reports sessions, screens and crashes on its own. Upload the dSYM for a build and the wall of memory addresses turns back into your own functions and line numbers.

No credit card required. Free tier available. The same SDK also gives you a database, cloud functions and remote config.

AppDelegate.swift · UIKit Live
import UIKit
                        import AppAmbit
                         
                        @main
                        class AppDelegate: UIResponder, UIApplicationDelegate {
                            func application(
                                _ application: UIApplication,
                                didFinishLaunchingWithOptions options:
                                    [UIApplication.LaunchOptionsKey: Any]?
                            ) -> Bool {
                                // the whole integration
                                AppAmbit.start(appKey: "<YOUR-APPKEY>")
                                return true
                            }
                        }
Sessions, screens and crashes start from that call. AppAmbitSdk 1.2.0
One

Line at launch. That is the whole integration.

12

Minimum iOS version. iPhone and iPad.

2

Languages, one SDK. Swift and Objective-C.

0%

No data lost offline. It queues and sends later.

The whole API

Six calls. That is the surface.

You have already written the first one. The rest are there when you want them, and every one is called the same way from Objective-C.

AppAmbit.start(appKey:)

The one you always write

Called once at launch, from your App init in SwiftUI or from didFinishLaunchingWithOptions in UIKit. Everything else on this page keys off it.

Analytics.trackEvent(eventTitle:data:)

Track what matters

A named event with a dictionary of string values. The session, device and screen trail are already attached for you.

Crashes.logError(exception:properties:)

Report a handled error

Catch it, log it, carry on. The error lands beside your crashes with the same session context and your own properties.

Crash monitoring

Crashes.logError(message:)

Log without an exception

For the cases where you have a message and no NSError to hand. Same destination, same context.

Crashes.generateTestCrash()

Prove it works

Fire a deliberate crash on a debug build, then watch a real report arrive and put the dSYM through its paces before you ship anything to users.

Analytics.enableManualSession()

Take over sessions

Automatic sessions are the default. Turn them off and drive startSession and endSession yourself when your app needs that control.

Get an App Key

That is the whole surface. The key that makes those calls report takes a minute to create.

Crashes you can read

An address is not a bug report. Give it the dSYM.

A release build strips the names out. What arrives is a thread backtrace of memory addresses, which tells you nothing on its own. Upload the dSYM archive for that build and AppAmbit resolves your frames back into functions and line numbers.

01

Upload the dSYM for that build

Drop the archive on the crash in your dashboard. It is stored against that version, so every crash from the same build can use it.

02

Symbolicate the crash

AppAmbit pulls the DWARF file out of the archive, checks it belongs to the same binary as the crash, and resolves your addresses. You get a notification when it finishes.

03

Read it, or take it with you

The symbolicated report opens in the dashboard and downloads as text, so it can go straight into an issue.

Handled errors from Crashes.logError arrive readable already. Symbolication is for the native crash reports, where the frames are addresses. More on crash monitoring.

Thread 0 crashed · MyApp 1.4.2 Symbolicated
0 MyApp 0x0000000104a3c8d4 0x1049f8000 + 281812 CartViewModel.applyCoupon(_:) CartViewModel.swift:88
1 MyApp 0x0000000104a41b20 0x1049f8000 + 302880 CheckoutView.body.getter CheckoutView.swift:41
2 MyApp 0x0000000104a2f0ac 0x1049f8000 + 225452 MyApp.init() MyApp.swift:12
3 SwiftUI 0x00000001b7d41f30 0x1b7c00000 + 1318192 0x00000001b7d41f30 0x1b7c00000 + 1318192
4 UIKitCore 0x00000001a2c4f8a0 0x1a2a00000 + 2422944 0x00000001a2c4f8a0 0x1a2a00000 + 2422944

Your three frames carry names. The system frames stay as they are: your dSYM only holds the symbols of your own binary.

See a readable crash

Upload a dSYM once and the next crash arrives with your own function names on it.

Session timeline

Screen changes are recorded without you writing them.

The SDK records screen-change breadcrumbs by itself, and the session timeline stitches them together with app lifecycle, connectivity changes, your own events and any errors. When a crash arrives, the run-up to it is already attached.

The one thing worth doing is naming your screens, so the trail reads like your app instead of like a class list.

Naming a screen · SwiftUI and UIKit
// SwiftUI
                        NavigationStack {
                            CartView()
                                .navigationTitle("Cart")
                        }
                         
                        // UIKit
                        viewController.title = "Cart"
LifecycleApp launched · 1.4.2 on iPhone 15, iOS 17.4
ScreenHome · recorded automatically
ScreenCart · recorded automatically
Eventcoupon_applied · code SUMMER, cart 42.90
ConnectivityWent offline · queued on the device
ConnectivityBack online · the queue is sent in batches
CrashCartViewModel.applyCoupon(_:) · sent on next launch

A session, as the dashboard replays it.

See a session timeline

The screens, the events and the crash arrive as one story you can read from the top.

Same SDK, same App Key

Reporting is where it starts, not where it stops.

Everything below is documented for iOS and reachable from the same install. Nothing new to add, nothing else to pay for.

App Analytics

Sessions, devices and iOS versions, drawn from what the SDK already sends the moment it starts.

App Analytics

Event Tracking

The events you name yourself, with their properties kept on every occurrence and grouped in the dashboard.

Event Tracking

Session Timeline

Every crash arrives inside the session it happened in, next to the events and logs that came before it.

Session Timeline

Breadcrumbs

The trail of steps that led to the crash, so you are reading a path rather than guessing one.

Breadcrumbs

Remote config

Flip a flag or change a value and your app picks it up, with no rebuild and no wait behind App Review.

Remote config

App Database

Real SQL from your iOS app, with no server to run and no connection string compiled into the binary.

App Database

Cloud Code

Call a Node.js function you deployed inside AppAmbit straight from Swift, and keep the secret out of the app.

Cloud Code

Content management

Read published content types and entries from the SDK, so copy and screens can change without a release.

CMS guide

Push notifications

Your APNs credentials, our delivery. One extra pod, and the devices are already registered against your App Key.

Push notifications

Build delivery

Hand a signed .ipa to your testers over a link, and see who is running which one.

Build delivery

AI Agent over MCP

Point Claude or Cursor at AppAmbit over MCP and let it read your crashes and sessions, or set the backend up for you.

AI Agent

AI App Builder

Ask Claude or Cursor for a feature and let it provision the backend that feature needs, on this same account.

AI App Builder
Open an account

Everything on this row is included, on the same App Key and the same free tier.

Build delivery

Your testers get the build the minute CI is green.

Connect the repository once and each pipeline hands its .ipa to AppAmbit with the branch, commit and author attached. Testers install from a link, and the crashes they hit land in the same place as everything else.

How release distribution works

GitHub Actions

Archive and export your .ipa in a workflow and let the signed webhook hand it straight to AppAmbit.

Bitbucket Pipelines

Wire a pipeline step to publish each build, with the branch, commit and author carried along.

Azure DevOps

Connect an Azure pipeline and every green build shows up ready to send to your testers.

Distribute your first build

Connect the repository, and testers install from a link instead of waiting on a store.

Setup

Three steps, and you are reporting.

Create your app in the dashboard to get an App Key, then touch three files in Xcode. There is no wrapper to write and no build phase to add.

01

Add the SDK

Either package manager, both from the same source. In Xcode it is File > Add Package Dependencies with the repository URL, Up to Next Major Version from 1.2.0. With CocoaPods 1.10 or later it is one line in the Podfile, then pod install.

// Package.swift
                            dependencies: [
                                .package(
                                    url: "https://github.com/AppAmbit/appambit-sdk-ios",
                                    from: "1.2.0"
                                )
                            ],
                            targets: [
                                .target(name: "MyApp", dependencies: [
                                    .product(name: "AppAmbit", package: "appambit-sdk-ios")
                                ])
                            ]
# Podfile
                            target 'MyApp' do
                              pod 'AppAmbitSdk', '~> 1.2.0'
                            end
02

Allow the connection

App Transport Security has to know it may reach AppAmbit, so the SDK can send what it collects. Same in either language.

Info.plist
<key>NSAppTransportSecurity</key>
                        <dict>
                            <key>NSExceptionDomains</key>
                            <dict>
                                <key>appambit.com</key>
                                <dict>
                                    <key>NSIncludesSubdomains</key>
                                    <true/>
                                </dict>
                            </dict>
                        </dict>
03

Start it at launch

One call with the App Key from your app's Info page. Sessions, device information, screen breadcrumbs and crash reporting begin from there.

AppDelegate.swift AppDelegate.m
import AppAmbit
                             
                            // in your App init(), or in didFinishLaunchingWithOptions
                            AppAmbit.start(appKey: "<YOUR-APPKEY>")
#import "AppAmbitSdk/AppAmbitSdk-Swift.h"
                         
                        // in application:didFinishLaunchingWithOptions:
                        [AppAmbit startWithAppKey:@"<YOUR-APPKEY>"];

Pick one and stay with it: the two package managers are not meant to sit in the same target. On the CocoaPods route, pod install and open the .xcworkspace from there on. The full walkthrough is in the getting started guide.

Create your App Key

Step one is a free account. The other two take about five minutes.

Push notifications

One more pod, not another vendor.

Push runs on the same App Key and the same install. You bring the APNs credentials from your Apple Developer account, AppAmbit keeps the device tokens, and you send from the dashboard or from a Cloud Code function.

Add AppAmbitPushNotifications next to the core library, the pod or the package product. Push needs Xcode 16 and Swift 6, a step above the core SDK.
Turn on the Push Notifications capability for the target. Without the aps-environment entitlement no token is ever delivered.
In SwiftUI, adopt AppAmbitAppDelegate with @UIApplicationDelegateAdaptor so the SDK sees the APNs callbacks. UIKit keeps its own delegate.
How push notifications work
Starting push · Swift
import AppAmbit
                        import AppAmbitPushNotifications
                         
                        // in your App init(), or in didFinishLaunchingWithOptions
                        PushNotifications.start()
                        AppAmbit.start(appKey: "<YOUR-APPKEY>")
                         
                        // ask when the moment makes sense, not at first launch
                        PushNotifications.requestNotificationPermission { granted in
                            if granted {
                                PushNotifications.setNotificationsEnabled(true)
                            }
                        }
Objective-C is the same two calls, from didFinishLaunchingWithOptions.
Set up push

Your own credentials, the tokens already tied to your App Key, and no second vendor to sign with.

Questions

Answered straight.

Does AppAmbit work with SwiftUI and UIKit?
Yes. The SDK is a plain iOS framework that you start once at launch, so it does not care which framework draws your screens. In SwiftUI you call AppAmbit.start(appKey:) from your App init, in UIKit from application(_:didFinishLaunchingWithOptions:), and the analytics and crash APIs are identical from there on.
How does dSYM symbolication actually work?
A crash arrives as an iOS crash report full of memory addresses. You upload the dSYM archive for that build, then symbolicate the crash from the dashboard. AppAmbit pulls the DWARF file out of the archive, checks it belongs to the same binary as the crash, resolves the addresses of your app into function names and line numbers, and notifies you when it is done. You can read the symbolicated report in the dashboard or download it as text.
Does it integrate with TestFlight?
No, and it is worth being clear about that. AppAmbit distributes builds itself: your pipeline sends the .ipa and your testers install it from a link, with the branch, commit and author attached. Treat it as an alternative for internal builds rather than an integration with TestFlight.
Can I use it from Objective-C?
Yes. Import AppAmbitSdk/AppAmbitSdk-Swift.h and call [AppAmbit startWithAppKey:@"<YOUR-APPKEY>"]. The analytics and crash APIs are available from Objective-C too, and every snippet in the documentation is shown in both languages.
What is the minimum iOS version?
iOS 12.0 and up, built with Xcode 13 or later. You can add the SDK with Swift Package Manager or with CocoaPods 1.10 or later, where the pod is called AppAmbitSdk. The source is on GitHub.
Can I keep my current crash reporter alongside it?
No, and that is true of any pair of crash reporters. Two libraries installing handlers for the same signals will fight over them, and you end up with reports missing from both. Remove the other one before you ship AppAmbit.
What happens when the device has no connection?
Nothing is lost. Sessions, events, logs and crashes are written to local storage while the device is offline, and the SDK sends everything that queued up in batches once connectivity returns. A crash is written to disk and sent on the next launch.

Building for the other platforms too? AppAmbit has an SDK for Android, React Native, Flutter, .NET MAUI, .NET and Avalonia. Each one takes its own App Key and reports into the same dashboard, on the same team and the same bill.

Try it on your own app

The free tier is enough to point the SDK at a real build and read your own sessions.

Ready when you are

Write the line. Watch the first session land.

Create a free account, paste your App Key into your App init, and run the app. The first session shows up while the simulator is still open, and the next crash comes back with your own file names on it. Swift or Objective-C, iOS 12 and up, no credit card.

One line, and iOS reports.

Start free