Available for the following Plan types:
Fullstory Enterprise*
Fullstory Business*
Fullstory Free
*with the following add-on:
Fullstory for Mobile Apps
Available to the following User roles:
Admin
Architect
Standard
Summary
Using Fullstory and Crashlytics together provides unparalleled insights into app issues so you can debug issues and iterate faster. When a crash is reported to Crashlytics, an engineer can use the session replay to see visually what the user did leading up to the moment of the crash.
The Goal
This documentation aims to provide common use cases for integrating Fullstory and Crashlytics and technical guidance on how to do so for iOS and Android. Feel free to contact Fullstory Support for more information, or share your success story with us!
Use Cases
Add a Fullstory session replay link to a Crashlytics report
With Fullstory for mobile apps, you can retrieve a link to the beginning of the session replay to be attached to the Crashlytics report. When viewing an issue in Crashlytics, navigate to the session replay link and watch the steps to reproduce without ever having to coordinate with end-users to get their feedback about what happened. This enables engineers to quickly and accurately reproduce the crash and fix the issue.
Capture user journeys along with app state
In addition to sharing a replay link, you can also share point-in-time data via logging. At any point in your application, you may wish to log certain messages to Crashlytics and Fullstory, so you can easily navigate back and forth between Crashlytics and Fullstory to find valuable information about specific crashes and errors.
By logging the app state as your users journey through your app, you can easily trace back the cause of an exception as it relates to user interaction and also understand the app state when the crash occurred.
Identify users who experienced a crash
When diagnosing and working with an issue, it’s often helpful to zoom-in to a certain set of users to understand how they are affected. Both Fullstory and Crashlytics allow you to identify the user by setting a userID. Navigate between Fullstory and Crashlytics for a user and have side by side data for the chosen user.
Prioritize non-fatal Errors
Non-fatal errors can still have a negative impact on user experience. While trying to understand your users’ overall experience, it may be valuable to investigate how non-fatal errors are getting in their way. Certain non-fatal errors may be caught and handled but may still stop your users from being able to use key functionalities and thus cause frustration and churn. Use custom events in Fullstory to surface any errors that may have negative impact. All custom events are indexed, which means you can search for non-fatal errors and prioritize them accordingly.
Implementation
Add a Fullstory session replay link to a crash report
- Set up your Crashlytics SDK and get crash reports via Crashlytics
- Set up Fullstory data capture for Android or iOS
- Implement your app to respond when Fullstory is ready:
Android Extend your Activity to implement FSOnReadyListener and override the onReady method. onReady is called when Fullstory is initialized and has FSSessionData ready. So you can retrieve the session URL using FS.getCurrentSessionURL():
@Override
public void onReady(FSSessionData sessionData) {
Log.d("TAG", "FSSessionURL " + sessionData.getCurrentSessionURL());
...
}iOS Using the Fullstory delegate method called fullstoryDidStartSession(_ sessionURL: String), this will provide you with the session URL (no need to override the method).
func fullstoryDidStartSession(_ sessionUrl: String) {
print("FSSessionURL: ",sessionUrl)
...
}React Native
ES6 Promise
FullStory.onReady().then((result) => {
const replayStartUrl = result.replayStartUrl
print("FSSessionURL: ", replayStartUrl)
})
async/await
const result = await FullStory.onReady()
const replayStartUrl = result.replayStartUrl
print("FSSessionURL: ", replayStartUrl) - After retrieving the Fullstory session URL, use the following snippet to attach the sessionURL as a key-value pair to a Crashlytics report:
Android FirebaseCrashlytics instance = FirebaseCrashlytics.getInstance();
String sessionURL = sessionData.getCurrentSessionURL();
instance.setCustomKey("FSsessionURL", sessionURL);iOS Crashlytics.crashlytics()
.setCustomValue(sessionUrl, forKey: "FSURLSession")React Native ES6 Promise
crashlytics().setAttribute(’FSsessionURL’, result.replayStartUrl).then(() ⇒ {})
async / await
await crashlytics().setAttribute('FSsessionURL', result.replayStartUrl) - When a crash occurs, you will see an issue under Crashlytics in your Firebase console. Note that when an app crashes, the session will terminate, meaning that the end of this session is where the crash had occurred. In each session under the issue, you can go to the Keys tab, and see the Fullstory session URL:
Capture user journeys along with app state
- You can choose to send the session URL along with custom log messages to Crashlytics log, and also mark them in Fullstory playback using FS.event or FS.log:
Android String fsCustomEventTag = "CrashlyticLog";
String sessionURL = sessionData.getCurrentSessionURL();
String logMsg = "Higgs-Boson detected! Bailing out";
Map<String, String> eventVars = new HashMap<>();
eventVars.put("logMessage", logMsg);
// send FS event or log to be shown in the playback
FS.event(fsCustomEventTag,eventVars);
FS.log(FS.LogLevel.INFO, logMsg);
// Crashlytics:
instance.log(logMsg);
instance.log("Current FSSessionURL "+ sessionURL);
instance.log("Look for FS event in playback with tag: " + fsCustomEventTag);iOS let fsSessionURL = FS.currentSessionURL
let fsCustomEventTag: String = "CrashlyticLog"
let logMsg = "Higgs-Boson detected! Bailing out"
var eventVars = [String: String]()
eventVars["logMessage"] = logMsg
// send FS event or log to be shown in the playback
FS.event(fsCustomEventTag,properties: eventVars)
FS.log(with: FSLOG_INFO, message: logMsg)
// Crashlytics:
Crashlytics.crashlytics().log(logMsg)
Crashlytics.crashlytics()
.log("Current FSSessionURL \(String(describing: fsSessionURL))");
Crashlytics.crashlytics()
.log("Look for FS event in playback with tag: \(fsCustomEventTag)");React Native ES6 Promise
FullStory.getCurrentSessionURL().then((fsSessionURL ⇒ {
let fsCustomEventTag = "CrashlyticLog"
let logMsg = "Higgs-Boson detected! Bailing out"
var eventVars = {}
eventVars["logMessage"] = logMsg
// send FS even or log to be shown in the playback
FullStory.event(fsCustomEventTag, eventVars)
FullStory.log(FullStory.LogLevel.Log, logMsg)
// Crashlytics:
crashlytics().log(logMsg).then(() ⇒ {})
crashlytics().log(`Current FSSessionURL ${fsSessionURL}`).then(() ⇒ {})
crashlytics().log(
`Look for FS event in playback with tag: ${fsCustomEventTag}`,
).then(() ⇒ {})
})
async / await
let fsSessionURL = await FullStory.getCurrentSessionURL()
let fsCustomEventTag = "CrashlyticLog"
let logMsg = "Higgs-Boson detected! Bailing out"
var eventVars = {}
eventVars["logMessage"] = logMsg
// send FS even or log to be shown in the playback
FullStory.event(fsCustomEventTag, eventVars)
FullStory.log(FullStory.LogLevel.Log, logMsg)
// Crashlytics:
await crashlytics().log(logMsg)
await crashlytics().log(`Current FSSessionURL ${fsSessionURL}`)
await crashlytics().log(
`Look for FS event in playback with tag: ${fsCustomEventTag}`,
) - View your custom logs for an issue under the Logs tab:
- Then you can navigate to the Fullstory session URL. You will see custom events on the right hand pane during replay, and custom logging will show up under dev tools to allow you to identify the point of time when the logs were sent to Crashlytics. These app state breadcrumbs help you better understand the exception.
- See the logs and event in Fullstory playback like below:
Notice the blocked-out areas of the app visible during replay. These are our default privacy controls in action. To learn more about how we’ve designed our privacy controls for mobile apps, check out this article on our engineering blog: https://bionic.fullstory.com/private-by-default-mobile-analytics/
Set user identifiers across Fullstory and Crashlytics
- When you are able to identify the user, you can send the user identity to Crashlytics
- At the same time, send the same user ID to Fullstory using FS.identify, with optional userVars, to help you identify users that experience a crash.
Android // when user is identified(logged in), create a Map for the userVars
Map<String, String> userVars = new HashMap<>();
userVars.put("userID", "testuser3");
userVars.put("displayName","crashlytics user3");
userVars.put("email","testeamil@gmail.com");
// send user identity and userVars to FS
FS.identify(userVar.get("userID"),userVar);
// send user identity to Crashlytics
instance.setUserId(userVar.get("userID"));iOS // when user is identified(logged in), create a Map for the userVars
var userVars = [String: String]()
userVars["userID"] = "testuser3"
userVars["displayName"] = "crashlytics user3"
userVars["email"] = "testeamil@gmail.com"
// send user identity and userVars to FS
FS.identify("testuser3", userVars: userVars);
// send user identity to Crashlytics
Crashlytics.crashlytics().setUserID("testuser3")React Native ES6 Promise
// when user is identified(logged in), create a Map for the userVars
var userVars = {}
userVars["userID"] = "testuser3"
userVars["displayName"] = "crashlytics user3"
userVars["email"] = "testemail@gmail.com"
// send user identity and userVars to FS
FS.identify("testuser3", userVars);
// send user identity to Crashlytics
crashlytics().setUserID("testuser3").then(() => {})
async / await
// when user is identified(logged in), create a Map for the userVars
var userVars = {}
userVars["userID"] = "testuser3"
userVars["displayName"] = "crashlytics user3"
userVars["email"] = "testemail@gmail.co"
// send user identity and userVars to FS
FS.identify("testuser3", userVars);
// send user identity to Crashlytics
await crashlytics().setUserID("testuser3") - By doing this you are now able to view and identify issues in Crashlytics by how many users are affected:
- User ID is also shown in the Data tab under an issue:
- Search for a certain user to investigate any user that is affected by crashes (Note that Fullstory does not capture crash events for iOS as of right now, but you can still see all the sessions from a certain user without adding the crashed event filter):
- Optionally, build your own deep link into Fullstory to be passed into Crashlytics, or vice versa:
<FS_USER_LINK> = https://app.fullstory.com/ui/<ORG_ID>/segments/everyone/people:search:(:((UserAppKey:==:<USER_ID>)):():():():)/0
Android only:<FS_USER_CRASH_LINK> = https://app.fullstory.com/ui/<ORG_ID>/segments/everyone/people:search:(:((UserAppKey:==:<USER_ID>)):():(((EventType:==:%22crashed%22))):():)/0
Get a list of crashes for specific users in Crashlytics by searching for a user ID, getting the link from your browser, something like this:<CRASHLYTICS_LINK> = https://console.firebase.google.com/u/0/project/<PROJECT_NAME>/crashlytics/app/<PLATFORM:APP_ID>/search?time=last-seven-days&type=crash&q=<USER_ID>
-
Pass the deep links into Fullstory or Crashlytics. Note that a different keys should be used for each deep link, if the same key is used, the latest value being passed will override the previous ones:
Android // optionally attach the user specific links between platforms
// Hardcoding the query link, use with caution
Map<String, String> userVars = new HashMap<>();
// call setUserVars or you can set these vars during identify
userVars.put("crashlyticsURLAndroidDemoapp",<CRASHLYTICS_LINK>);
FS.setUserVars(userVar);
// add FS links to the crash report as custom key
instance.setCustomKey("FSUserSearchURL",<FS_USER_LINK>);
instance.setCustomKey("FSUserCrashedSearchURL",<FS_USER_CRASH_LINK>);iOS var userVars = [String: String]()
// call setUserVars or you can set these vars during identify
userVars["crashlyticsURLiOSDemoApp"] = <CRASHLYTICS_LINK>
FS.setUserVars(userVars);
// add FS links to the crash report as custom key
Crashlytics.crashlytics()
.setCustomValue(<FS_USER_LINK>, forKey: "FSUserSearchURL")React Native ES6 Promise
// call setUserVars or you can set these vars during identify
userVars["crashlyticsURLRNDemoApp"] = <CRASHLYTICS_LINK>
FullStory.setUserVars(userVars)
// add FS links to the crash report as custom key
crashlytics()
.setAttribute('FSUserSearchURL', <FS_USER_LINK>).then(() => {})
async / await
// call setUserVars or you can set these vars during identify
userVars["crashlyticsURLRNDemoApp"] = <CRASHLYTICS_LINK>
FullStory.setUserVars(userVars)
// add FS links to the crash report as custom key
await crashlytics()
.setAttribute('FSUserSearchURL', <FS_USER_LINK>) - Now you are able to go back and forth when investigating a certain crash like so:
- Identify a user in Crashlytics:
- Get the link to the Fullstory session replay so you can see all the crashes from all users or just the current user. Feel free to build on top of these prebuilt links and create your own search or segment.
- For Android, retrieve all crashes:
- For Android, retrieve all crashes:
- Get the most recent URL to Crashlytic's user search page, so you can go directly to see all the crashes for this user:
- Identify a user in Crashlytics:
Send Fullstory events during non-fatal exception handling
- Crashlytics automatically reports fatal crashes, but you can optionally send non-fatal crashes when you catch one
- You can also send a log or an event to Fullstory to help you pinpoint the error when it happens during session replay
Android try {
// your code that throws an Exception here
}catch (Exception e){
// record the Exception to Crashlytics
FirebaseCrashlytics.getInstance().recordException(e);
// Send the error to FS
Map<String, String> eventVars = new HashMap<>();
eventVars.put("errorMessage", e.getMessage());
FS.event("nonFatalException",eventVars);
FS.log(FS.LogLevel.ERROR,e.getMessage());
}iOS do {
// your code that throws an Exception here such as:
throw NSError(domain: "TestDomain", code: 404, userInfo: nil)
}catch {
// code to handle your error
// record the Exception to Crashlytics
Crashlytics.crashlytics().record(error: error)
// Send the error to FS via event or log
var eventVars = [String: String]()
eventVars["errorMessage"] = error.localizedDescription
FS.event("nonFatalException",properties: eventVars)
FS.log(with: FSLOG_ERROR, message: error.localizedDescription)
}React Native ES6 Promise new Promise((resolve, reject) => {
// your code that throws an Exception here
}).catch(e => {
// code to handle your error
// record the Exception to Crashlytics
crashlytics()
.record(e)
.then(() => {})
// Send the error to FS via event or log
var eventVars = {}
eventVars.errorMessage = e.message
FullStory.event('nonFatalException', eventVars)
FullStory.log(FullStory.LogLevel.Error, e.message)
})
async / await
try {
// your code that throws an Exception here such as:
throw new Error('Error message')
} catch (e) {
// code to handle your error
// record the Exception to Crashlytics
await crashlytics().record(e)
// Send the error to FS via event or log
var eventVars = {}
eventVars.errorMessage = e.message
FullStory.event('nonFatalException', eventVars)
FullStory.log(FullStory.LogLevel.Error, e.message)
}
This will help you pinpoint the non-fatal error that occurred during a user session:
- Pinpoint the error occurrence in Fullstory playback
- In this case even though the exception is non-fatal and did not crash the app, it prevents your user from clicking on “purchase” button
- You can easily build searches and filters to identify the most crucial exceptions in your workflow:
- Once you’ve pinpointed the exception that you would like to prioritize, you can then view the non-fatal exceptions in Crashlytics