Utilities is composed of a set of tools to fine-tune the operation and management of your application in Countly. Nested is this section of your Main Menu, you will find:
Data Manager
Please refer to the detailed Data Manager User Guide.
Data Populator
The Data Populator feature is available in both Enterprise and Community editions.
The Data Populator feature provides an easy method for you to generate sample data for your currently active application. It populates data related to sessions, events, crashes, in-app purchases, push notifications, and user profiles so that you can have an understanding of what your reporting and analytics will look like when you go live.
Getting Started
To start using the Data Populator feature, go to Main Menu > Utilities > Data Populator. The data populator will warn you before you populate the data into any app. It is important that you do not run the data populator if your current application has already collected real/live user data.
Data Populator Overview
Understanding Data Populator Views
The Data Populator feature is divided into two Views:
- Data Populator: This allows you to set up and run the data populator on the selected application.
- Templates: This allows you to set up different data population templates, including the details you want to populate (e.g., events, sessions, funnels, etc.), and save them for use.
Using Data Populator
Data Populator View
The Data Populator View is the default View in the Data Populator feature.
On this page, you need to set the below fields:
- App Template: Using the dropdown menu, select the template you want to use to populate sample data.
- Date Range: Using the calendar dropdown, set a date range for the sample data. The options mimic the options in the date range of all Countly features.
- Maximum Time to Run: Set the maximum time, in seconds, that the data population should run.
Once you have filled in these fields, click the Generate Demo Data button. This will result in sample data being populated.
Do not populate sample data for an app that is already collecting live/real user data!
Templates View
To go to the Templates View, click on the Templates tab at the top of the page. Here, you will see a table of all the templates that you have set up.
Each template has the below details:
- Template: The name of the template.
- Type: Whether this is a default or custom template.
- Number of User Properties: Number of user properties within the template.
- Number of Events: Number of events within the template.
- Edited By: The user who last edited the template.
Duplicating a Template
To duplicate any template, click on the 3-dot ellipsis menu button on the right of the row of the relevant template, and then click on Duplicate.
Creating a New Template
To create a new template, click on the Create New Template button on the top right corner of the page. This will open up a drawer where you will be required to fill in the below details:
- Template Name
- Custom User Properties (including key and values)
- Additional Custom User Properties (Optional): Click on the +Add a custom property button to add additional user properties. To delete any user property, click on Delete Property at the top right of the field.
- Event, including:
- Event Key
- Segmentation
- Values
- Use Duration Property: Check this box to set a minimum and maximum time that it may take for a user to complete actions inside the app.
- Use Sum Property: Check this box to set a range for a floating point number to track an additional numeric value for your event.
- Additional Segmentations (Optional): Click on the +Add Segmentation button to add additional segmentation to the Event.
- Additional Events (Optional): Click on the +Add Event button to add additional Events and their details. To delete any Event, click on Delete Event at the top right of the field.
Once you have filled in all the details, click on the Create button at the bottom right of the drawer. The template will now be added to the table.
Config Transfer
The Config Transfer feature is available only in the Enterprise edition.
The Config Transfer feature allows you to export the configurations of other features into another instance of Countly. You can export entire A/B testing experiments or Dashboards, and import them to a completely different Countly instance.
Feature Dependencies
Config Transfer of data from specific features is dependent on the availability of those features in the edition you are using. As such, Config Transfer can be implemented in:
- A/B Testing
- Cohorts
- Dashboards
- Formulas
- Funnels
- Data Populator
- Remote Config
- Ratings
- Data Manager Transformations
Getting Started
To start using Config Transfer, go to Main Menu > Utilities > Config Transfer. The default View is the Export Configs View.
Config Transfer Overview
Understand Config Transfer Views
The Config Transfer feature has two Views:
- Export Configs: This View allows you to export configs. It is the default Config Transfer view.
- Import Configs: This View allows you to import configs.
Using Config Transfer
Exporting Configs
To start exporting configs, go to Main Menu > Utilities > Config Transfer. The default view is the Export Configs View.
On the left side of this View (1), you will see all the feature configurations that can be exported. Use the dropdown arrow against any feature configuration to see items under it.
Use the Search bar at the top of the table to look for specific feature configurations. To select any feature configuration to export it, simply select the corresponding check box (2). Select as many feature configurations as you would like to export. You can also select individual items of a particular configuration using the collapsible arrow (3) on the right side of each configuration. As you select configurations, they appear in the Configs to Export table on the right side (4).
To deselect any of the plugin configurations, unchecking them in either the left or right table removes them from the selection to be exported.
You can then download these files to export them. To download the JSON file, you can simply click on the Export as File button (5).
Importing Configs
To import configs, click on the Import Configs tab at the top of the page and go to the corresponding view.
A file downloaded from the Export Config section from any Countly instance can be uploaded in this section by clicking the Browse Link or by dragging and dropping the file onto the white upload area.
Once the file has been selected, the import process can be started by clicking the Import Configs button on the top right corner of the upload area.
The imported configurations will be visible in their respective sections, e.g., imported dashboards would be visible in the Dashboards dropdown.
Dependencies
The dependencies for each exported item are exported and then imported into the new instance without any extra configuration.
For example: If Dashboard A depends on Cohorts x and y, both Cohorts x and y will be exported with the file as well.
Incoming Data Logs
The Incoming Data Logs feature is available in both Community and Enterprise Editions.
Incoming Data Logs allows you to centralize all the incoming requests from your SDKs, allowing you further explore all requests received, request time, app version, device, location, crashes, performance, and other metrics of the requests.
Getting Started
First of all, make sure Event Logs is enabled. To do so, go to the Sidebar > Management > Feature Management and enable the Incoming Data Logs toggle.
Then, to access Incoming Data Logs at any time, on the Main Menu, go to Utilities > Incoming Data Logs.
Incoming Data Logs Overview
Understanding Incoming Data Logs
This feature logs all requests, originating device, and contents of the latest 1000 requests done to the SDK, something particularly useful during the development stage of your application.
In addition, the logs' data can be segmented based on different types of requests such as sessions, events, metrics, user details, and crashes.
Using Incoming Data Logs
The Incoming Data Logs View includes everything you need to know about the last 1000 requests done with the SDKs to your app.
1. You can visualize all the requests (selected by default) or filter per type. Note that the type will depend on the data types currently being collected by your SDKs.
2. Additionally, you can enable the Auto-refresh toggle button (disabled by default), which will automatically update the logs.
3. Each log entry is shown in a human-readable format. Upon expanding the content of each entry, you will find the actual information sent by the SDK.
Location Targeting
The Location Targeting feature is available only in the Enterprise Edition.
Location Targeting allows you to create specific geolocations to use for Push Notifications. Therefore, you will only see this option if your Countly instance corresponds to a mobile application.
First of all, make sure Location Targeting is enabled. To do so, in the Sidebar, go to Management > Feature Management and enable the Geolocations toggle.
After that, you will find Location Targeting in the Utilities section.
There, the View will show you a list of existing geolocations (including the given name, applications in Countly that can use them, and specfic location) as well as the + Create New Location button
By default, the location will be available for all applications, unless you select a specific application.
Compliance Hub
The Compliance Hub feature is available in both Community and Enterprise Editions.
- Supported Countly versions: 18.04 and higher
- Supported Countly SDKs: iOS, Android, Node.js, and web
The Countly Compliance Hub feature helps Countly administrators view and track users' consents, and manage them in one place.
Getting Started
Compliance Hub is enabled by default on each Countly instance and helps you do two things:
- Collect user consents: Every first-time user/visitor (in web or mobile) should be asked for permission to collect analytics data. This data has several features (e.g. session, crash, view, clicks, etc.) and it should be clearly stated which data would be collected from the end user via a consent form. If a user does not give consent for data collection, no information will be sent until they clearly opt-in.
- Manage user requests: This feature also creates a "Consents" tab for each user profile (available only in the Enterprise Edition). Any user, in mobile or web, can request their information exported or deleted via a contact form or via an SDK. When a request is retrieved from an SDK, this information can be viewed from that particular user's profile page. Upon reviewing this request, the Countly admin can either export this data and send it to the corresponding user, or delete the user's information altogether.
In order to collect consent, you can use a custom form, or use a form that we provide as examples for each SDK. When you have more than one vendor integrated in your app that collects user data, it is best to use a custom consent manager which will inform those SDKs.
Compliance Hub Overview
SDK Capabilities
Countly SDKs for mobile (iOS and Android) and web pages (Nodejs and web SDK) have the ability to get consent information from users and then send this data to Countly. The SDKs can separately send different individual metric data in case it is required (e.g., metrics, sessions, users, and crashes), send all of them, or not send them at all.
The SDKs can also send feature-based opt-in/opt-out requests for logging purposes for a specific device, instead of a particular user. Hence, users must send their opting choices for each device they have.
Each SDK is initialized without sending any information to a Countly server, and it is possible for each SDK to enable or disable a metric submission feature while the application is running. Hence, a user can opt-in for all metrics, but then decide to opt out from some of them. If there is queued data related to a user, and they choose to opt out, this queue is not sent to Countly.
The SDKs are configured as opt-in by default due to backward compatibility, as is the most common use case for first-party data collection. It is however possible to set an SDK into opt-out mode with the initialization configuration. In such a case, it would work only when specific consents are provided.
Getting Permissions via the SDKs
In order to comply with GDPR, you need to set all your visitors at 'opt-out' by default, and show them a consent form pop-up. At your discretion, in regions where it may be legal to do so, you can also opt-in your users by default and not show this consent form. However, for GDPR you must explicitly ask for permission to track data, explaining what you are tracking and why. Only when the user agrees can you start tracking your users.
When the app starts for the first time, it initializes Countly only after permission is given explicitly by the end user. In your application, you need to give the user a way to opt in/out in case the user changes their mind, and this method is provided by Countly SDKs.
If you want to have a feature by feature (e.g., metrics, users, crashes, views, etc.) selection, such as opt-in to crash submissions, but opt-out of views, you would need to manage the user preferences yourself, storing them persistently and starting or calling Countly features enabling methods based on those preferences upon each app start. There are examples of how to do that inside each SDK documentation where sending consent information is supported.
Using Compliance Hub
The Compliance Hub feature is enabled by default in all Countly instances. If, for some reason, you would like to disable it, go to Side Bar > Management > Feature Management and disable the Data Compliance Hub toggle.
To use Compliance Hub, go to Main Menu > Utilities > Compliance Hub.
The Compliance Hub feature has four Views:
- Metrics: View data compliance metrics (e.g., sessions, events, views, clicks, forms, users, etc.) per metric, in a time-series graph. It shows all incoming requests about consents, e.g., both opt-ins and opt-outs.
- Users: A visitor list with consent history. In this View, you can see each visitor's consent history and also export data of the corresponding user.
- Consent History: List of all opt-in and opt-out requests, based on any metrics (e.g., sessions, events, views, etc.)
- Export/Purge History: List of all exports and removals in a single view.
Other than the information above, each user profile (available in Enterprise Edition) has a tab titled Consents, which keeps the user's consent history. If you see a user sending export or deleting consent, you can just export this user's data or remove this user's information altogether from Countly.
These are detailed below.
Metrics View
In the Metrics View you can view all consent requests in a time-series graph, including opt-ins or opt-outs for each feature as shown below. In this screen, orange lines represent opt-outs and blue lines represent opt-ins. You can also filter by metric feature type, e.g., opt-ins and opt-outs by sessions, events, crashes, etc. from the Feature type dropdown menu. You can also showcase data for specific periods using the time buckets on the top right.

Users View
In the Users View, you can see all users' current consent options, broken by User ID, Device, App Version, and Consent Type.

On the right end of each user row, there is a 3-dot ellipsis menu where you can:
- Go to consent history: Clicking this option will take you to the consent history of that particular user.
- Download user's export data: Downloads user's exported data, including everything that this particular user's device has sent over, e.g., crashes/errors (if any) or events.
Starting version 22.09.15 export format has been changed. Export is a single .json file. There is an array of objects, in which each describes a single document in different collections.[
All fields except _col are coming from the database. _col is the collection from which data was exported. Before version 22.09.15 downloaded package is in a gzip format (.gz) which includes several JSON files.
....
{"_col":"metric_changes63ef551128bad91a3c11d3e7","brw":{"o"...},.......},
{"_col":"app_users63ef551128bad91a3c11d3e7",......},
.....
]
- Download user's export data: Downloads user's exported data, including everything that this particular user's device has sent over, e.g., crashes/errors (if any) or events.
- Purge user's exported data: It completely deletes user's exported data on the server. This does not remove the user data.
- Purge user's data completely: It deletes user data completely. Use with caution!
You can download the data table information using the Downward Arrow button on the top right of the table.
Exporting vs Purging application user data
Neither exporting nor deleting exported data removes the application user's data directly. In order to purge an application user, you must use Purge user's data completely from the list explained above. Use this menu item with extreme caution as this will completely wipe out that application user's past history from Countly.
Consent History View
In the Consent History tab, you will see a historical list of all past consents. You can filter by status, i.e., those who opted-in, opted-out, or all, and metric type (sessions, events, views, etc.). Once you set your desired filter, the data table shows you the user's Device ID, Changes (i.e., opted-in / opted-out), UID, Consent (i.e., features opted-in), App Version, and Time of last change. You can also select a date range for which to populate the data table using the Dropdown Menu button at the top right of the table.
Download the information from any data table by clicking the Downward Arrow at the top right corner.
Export/Purge History View
The Export/Purge History View shows you all export and data removals a Countly admin has executed. Whenever you export or delete user data, is shown here. You can filter them on the basis of data type using the Dropdown Menu button at the top left of the data table. You can also download the report by clicking on the Downward Arrow button at the top right of the table.
Individual User Consents
When the Compliance Hub feature is enabled, each User Profile will have a new tab, Consents. This shows the application user's consent history, along with several actions you can take.
When you click on the 3-dot ellipsis menu on top-right hand side of the screen, you will see 3 options by default:
- Export: Exports this app user's data and make it available for download later. This option does not directly download app user's data.
- Purge user's data completely: This option purges this app user's data. Use with caution!
- Create message: Opens the Push Notification panel so you can let this user know that their app data is being wiped. This option is only shown if the user has a push notification token obtained and sent via a mobile app. You can do this only before deleting the app user data, since push tokens will be invalidated.
When you export an app user data, there will be a 4th and 5th option shown here, Download user's exported data and Purge user's exported data, which downloads exported user data and deletes the exported data on Countly, respectively. Note that deleting exported data does not delete the user's data previously collected directly, and this user will be able to send data from the applications.
Compliance Hub APIs
Countly has several API sets that helps you remain compliant with several regulations in your country, or worldwide. This is useful especially if you send data to Countly not via SDKs, but via exposed Countly APIs.
Right to be forgotten: https://resources.count.ly/v1.0/reference#iapp_usersdelete
Right for retrieving user data: https://resources.count.ly/v1.0/reference#iapp_usersexport https://resources.count.ly/v1.0/reference#iapp_usersdeleteexportfilename https://resources.count.ly/v1.0/reference#oapp_usersdownloadfilename
Right for rectifying stuff (this is not in API, but in SDK):https://resources.count.ly/v1.0/reference#iapp_usersupdate
Symbolication Logs
The Symbolication Logs feature is available only in the Enterprise Edition.
The Symbolication feature lets you symbolicate/de-obfuscate crash reports and convert them into human readable format, helping you pinpoint where in your code a crash is originating from.
Getting Started
The first step for using symbolication is installing and enabling the Symbolication Logs feature.
To do so, in Countly, go to the Sidebar > Management > Feature Management and enable the Symbolication Logs toggle.
Setting up Symbolication Logs differs from platform to platform. In the Using Symbolication Logs section below, we delve into how to set it up for each platform. Before that, let's take a look at a few samples of symbolication logs to better understand this feature.
Symbolication Logs Overview
What are Symbolication Logs?
When releasing your application, you might be skipping crucial steps such as debugging information from the final binary format, obfuscating your source code, or minifying it by removing unnecessary characters. Doing all this can make your application harder to reverse engineer, but you may then receive error stack traces that have obfuscated information in them, making it impossible to track down the source of your crash.
Depending on the platform, your stack trace may be full of memory addresses or transformed function names. Symbolication is the process of converting them into human-readable, class/method names, file names, and line numbers.
Samples of Symbolication Logs
Android Symbolication Samples
java.lang.IllegalStateException: Could not execute method for android:onClick
at android.view.View$DeclaredOnClickListener.onClick(View.java:4725)
at android.view.View.performClick(View.java:5637)
at android.view.View$PerformClick.run(View.java:22429)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6121)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:889)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:779)
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Method.invoke(Native Method)
at android.view.View$DeclaredOnClickListener.onClick(View.java:4720)
... 9 more
Caused by: java.lang.Exception: Exception at the end of the call
at ly.count.android.demo.a.b(SourceFile:29)
at ly.count.android.demo.a.a(SourceFile:21)
at ly.count.android.demo.ActivityExampleCrashReporting.c(SourceFile:98)
at ly.count.android.demo.ActivityExampleCrashReporting.b(SourceFile:94)
at ly.count.android.demo.ActivityExampleCrashReporting.a(SourceFile:90)
at ly.count.android.demo.ActivityExampleCrashReporting.onClickCrashReporting10(SourceFile:82)
... 11 more
java.lang.IllegalStateException: Could not execute method for android:onClick
at android.view.View$DeclaredOnClickListener.onClick(View.java:4725)
at android.view.View.performClick(View.java:5637)
at android.view.View$PerformClick.run(View.java:22429)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6121)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:889)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:779)
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Method.invoke(Native Method)
at android.view.View$DeclaredOnClickListener.onClick(View.java:4720)
... 9 more
Caused by: java.lang.Exception: Exception at the end of the call
at ly.count.android.demo.Utility.void DeepCall_b()(SourceFile:29)
at ly.count.android.demo.Utility.void DeepCall_a()(SourceFile:21)
at ly.count.android.demo.ActivityExampleCrashReporting.void deepFunctionCall_3()(SourceFile:98)
at ly.count.android.demo.ActivityExampleCrashReporting.void deepFunctionCall_2()(SourceFile:94)
at ly.count.android.demo.ActivityExampleCrashReporting.void deepFunctionCall_1()(SourceFile:90)
at ly.count.android.demo.ActivityExampleCrashReporting.void onClickCrashReporting10(android.view.View)(SourceFile:82)
... 11 more
iOS Symbolication Samples
libsystem_platform.dylib 0x00000001826c130c _sigtramp + 36
mahya 0x000000010006e174 mahya + 156020
mahya 0x000000010006d060 mahya + 151648
mahya 0x000000010006ad34 mahya + 142644
UIKit 0x0000000189925d74 + 184
UIKit 0x00000001898eedb8 + 128
UIKit 0x00000001898ff2b0 + 88
UIKit 0x000000018a1c0ff8 + 272
UIKit 0x0000000189b5e138 + 280
UIKit 0x0000000189b5d96c + 1064
UIKit 0x0000000189b5d4c4 + 60
UIKit 0x000000018a1c0ff8 + 272
UIKit 0x0000000189b5d400 + 436
UIKit 0x00000001898eea40 + 672
UIKit 0x00000001898ee364 + 1780
UIKit 0x00000001898ec954 + 228
UIKit 0x00000001898eab04 + 3152
UIKit 0x0000000189b74750 + 228
UIKit 0x000000018975ea50 + 384
UIKit 0x0000000189b74400 + 344
UIKit 0x0000000189768fd4 + 2480
UIKit 0x000000018976436c + 3192
UIKit 0x0000000189734f80 + 340
UIKit 0x0000000189f2ea20 + 2400
UIKit 0x0000000189f2917c + 4268
UIKit 0x0000000189f295a8 + 148
CoreFoundation 0x00000001835b142c + 24
CoreFoundation 0x00000001835b0d9c + 540
CoreFoundation 0x00000001835ae9a8 + 744
CoreFoundation 0x00000001834deda4 CFRunLoopRunSpecific + 424
GraphicsServices 0x0000000184f49074 GSEventRunModal + 100
UIKit 0x0000000189799c9c UIApplicationMain + 208
mahya 0x000000010005fe14 mahya + 97812
libdyld.dylib 0x00000001824ed59c + 4
libsystem_platform.dylib 0x00000001826c130c _sigtramp + 36
-[MHViewController countlyProductionTest] (in mahya) (MHViewController.m:620)
-[MHViewController transitionToMahya] (in mahya) (MHViewController.m:443)
-[MHViewController textFieldShouldReturn:] (in mahya) (MHViewController.m:210)
UIKit 0x0000000189925d74 + 184
UIKit 0x00000001898eedb8 + 128
UIKit 0x00000001898ff2b0 + 88
UIKit 0x000000018a1c0ff8 + 272
UIKit 0x0000000189b5e138 + 280
UIKit 0x0000000189b5d96c + 1064
UIKit 0x0000000189b5d4c4 + 60
UIKit 0x000000018a1c0ff8 + 272
UIKit 0x0000000189b5d400 + 436
UIKit 0x00000001898eea40 + 672
UIKit 0x00000001898ee364 + 1780
UIKit 0x00000001898ec954 + 228
UIKit 0x00000001898eab04 + 3152
UIKit 0x0000000189b74750 + 228
UIKit 0x000000018975ea50 + 384
UIKit 0x0000000189b74400 + 344
UIKit 0x0000000189768fd4 + 2480
UIKit 0x000000018976436c + 3192
UIKit 0x0000000189734f80 + 340
UIKit 0x0000000189f2ea20 + 2400
UIKit 0x0000000189f2917c + 4268
UIKit 0x0000000189f295a8 + 148
CoreFoundation 0x00000001835b142c + 24
CoreFoundation 0x00000001835b0d9c + 540
CoreFoundation 0x00000001835ae9a8 + 744
CoreFoundation 0x00000001834deda4 CFRunLoopRunSpecific + 424
GraphicsServices 0x0000000184f49074 GSEventRunModal + 100
UIKit 0x0000000189799c9c UIApplicationMain + 208
main (in mahya) (main.m:16)
libdyld.dylib 0x00000001824ed59c + 4
JavaScript Symbolication Samples
ReferenceError: undefined_function is not defined
at r (file:///home/atak/Work/Countly/sample-app/dist/main.js:2:140)
at HTMLButtonElement.document.getElementById.onclick (file:///home/atak/Work/Countly/sample-app/dist/main.js:2:521)
ReferenceError: undefined_function is not defined
at undefined_function (src/index.js:30:4)
at cause_error (src/index.js:37:10)
Using Symbolication Logs
For the obfuscation and minification processes to be reversible, a symbol or mapping file is also produced while building your application. It is imperative for you to keep and archive those files as the symbolication process is only possible with them. You will also need to archive symbol files for every version you would like to symbolicate.
Currently, Countly supports symbolication for Apple-provided tools in iOS mobile applications, DexGuard and ProGuard in Android, and source maps in JavaScript web applications.
Setting up Symbolication for iOS
Setting up a connection to the Countly symbolication server is only needed for symbolicating iOS stack traces. You can skip it if you will not be using Symbolication for iOS applications.
For iOS applications, the next step after the one mentioned above in the Getting Started section is creating the connection to the Countly symbolication server. To do so, you will need a symbolication API key provided by Countly. The Countly symbolication server address is https://symbolication.count.ly. When you get your API key, you will need to set it in the server configuration screen in Management > Settings, under the Crashes section.
After you have made sure that those fields contain valid information, click the Test Connection button to make sure everything is working correctly. If your provided server URL or API key is wrong or your Countly server cannot reach the symbolication server, you will be able to diagnose it with this test button.
The symbol file is a dSYM file for iOS.
- A dSYM file is Apple's standard Mach-O file which contains debug symbols for a given build.
- It includes debug symbols for all architectures used for the build (e.g., armv7, arm64).
- Its size may vary depending on the original source code and libraries used in the project.
- It is a file-like folder structure, and actual dSYM data is in the binary file
AppName.app.dSYM/Contents/Resources/DWARF/AppName
.
dSYM Location
For each executable target (main app, extensions, and Cocoa Touch Frameworks) in the project, a separate dSYM file is generated when the project is built. The dSYM location depends on build settings. By default, it is defined by $DWARF_DSYM_FOLDER_PATH
Xcode Environment Variable.
An example location is: ~/Library/Developer/Xcode/DerivedData/AppName-abcdef0123456789/Build/Products/Release-iphoneos/AppName.app.dSYM
In addition, if you use the Product > Archive
option in Xcode to create the .xcarchive
of your app, you may find a dSYM already created inside the .xcarchive
. By default, its location is: ~/Library/Developer/Xcode/Archives/YYYY-MM-DD/AppName DD-MM-YYYY, HH.mm.xcarchive/dSYMs
Automatic dSYM Upload
For automatic dSYM, please see the Countly iOS SDK documentation here.
Setting up Symbolication for Android
Android's official tool for code shrinking and obfuscation is called ProGuard. A detailed description of its usage can be found here. There is also a paid tool with additional features called DexGuard. Both ProGuard and DexGuard can be used for Countly symbolication. Currently, we do not support any other Android obfuscation libraries.
If you are using Android Studio for development, the mapping files will not be produced when you make instant runs. For them to appear, you will need to either generate a signed APK or choose the Build APK option.
After the build is complete, the symbol file called mapping.txt
can be found under <module-name>/build/outputs/mapping/release/
or <module-name>/build/outputs/mapping/debug/
, depending on how you initiate the build process.
ProGuard Rules
You have the option of adding some rules to ProGuard (or DexGuard) and modifying how it runs. These rules should be added in the proguard-rules.pro file.
If you are deciding to use ProGuard, you have to keep in mind that it will rename the function and class names. Therefore, it will break the code that is using reflection if you don't take steps to stop this from happening. You may find more information on the ProGuard manual.
At the very least, you should include these lines in your ProGuard rule file:
-keep class org.openudid.** { *; }
-renamesourcefileattribute SourceFile
-keepattributes SourceFile,LineNumberTable
The first one is needed to prevent openudid
from breaking, and Countly uses it to generate user IDs. The second and third rules are needed to add source file and line number information to your Android stack traces.
The ProGuard rule file should be named proguard-rules.pro, and it is usually located in the root of your module. More information here.
Setting up Symbolication for JavaScript
In order to symbolicate errors, we need a source map file. We will try to lay out how you can produce a source map file for builds that use webpack, and you can also consult your build tool's documentation on how to generate one for your builds.
For this demonstration, we will use the sample frontend application that is available in the Countly web SDK repository. It is a simple project with just one source file src/index.js
that imports a third-party dependency, the Countly SDK, and binds a couple of buttons to throw errors.
import Countly from "countly-sdk-web"
Countly.init({
app_key: "YOUR_APP_KEY",
app_version: "1.0",
url: "https://try.count.ly",
debug: true
});
//track sessions automatically
Countly.track_sessions();
//track pageviews automatically
Countly.track_pageview();
//track any clicks to webpages automatically
Countly.track_clicks();
//track link clicks automatically
Countly.track_links();
//track form submissions automatically
Countly.track_forms();
//track javascript errors
Countly.track_errors();
//let's cause some errors
function cause_error(){
undefined_function();
}
window.onload = function() {
document.getElementById("handled_error").onclick = function handled_error(){
Countly.add_log('Pressed handled button');
try {
cause_error();
} catch(err){
Countly.log_error(err)
}
};
document.getElementById("unhandled_error").onclick = function unhandled_error(){
Countly.add_log('Pressed unhandled button');
cause_error();
};
}
We also have a webpack configuration that takes this source file, resolves its import, and minifies the resulting file, creating a single minified file dist/main.js. Also, note that we have set the devtool option to hidden-source-map
which means webpack will generate a source map file but will not reference it in the main.js file. This is typically ideal for production environments where you don't need to inspect the underlying code in the browser. You might want to go with source-map
in development environments; it will reference the source map file in main.js and ease debugging in the browser.
const path = require('path'); const webpack = require('webpack'); const TerserPlugin = require('terser-webpack-plugin'); module.exports = { mode: 'development', plugins: [new webpack.ProgressPlugin()], devtool: "hidden-source-map", module: { rules: [{ test: /\.(js|jsx)$/, include: [path.resolve(__dirname, 'src')], loader: 'babel-loader' }] }, optimization: { minimize: true, minimizer: [new TerserPlugin()], }, output: { devtoolModuleFilenameTemplate: '[resource-path]', devtoolFallbackModuleFilenameTemplate: '[absolute-resource-path]' } };
Here is a screenshot of how you would run the webpack with npx and use the webpack package that would be installed along with your project.
Then, you can see that webpack produced themain.js file along with its source map file main.js.map. Now, you just need to upload that source map file to your Countly instance.
Uploading the Symbol File
Now that the connection to the symbolication server has been established and the necessary symbol files are procured, we can delve into the symbolication of specific stack traces.
You should only upload one symbol file per application version. Multiple symbol file uploads are not supported.
To upload a symbol file, open the Manage Symbols section.
There, you will have to click on the Add Symbolication File button, which will open a drawer with the fields described below. Note that you will need to do this for every version of your app you would like to symbolicate.
Select Type: In the Type
selection, you need to choose the platform for the symbol file you are uploading.
Build ID: For Android, the Build ID
field is the version name. For iOS, the Build UUID
field is your app's Build UUIDs. For JavaScript, this must match the app_version
you use when initializing the Countly SDK in your web application.
You can get Build UUIDs
using the dwarfdump --uuid
command on the dSYM file, and you may specify more than one comma-separated Build UUID
for each architecture.
Note that the Android Build ID and iOS Build UUID specified here must match your app's corresponding Build ID or Build UUID.
Example:
dwarfdump --uuid CountlyTestApp-iOS.app.dSYM
UUID: AD4F5647-B2A0-3D85-8DF4-78D4DFD83296 (armv7) CountlyTestApp-iOS.app.dSYM/Contents/Resources/DWARF/CountlyTestApp-iOS
UUID: 70B0DE66-D337-3952-914D-A1E542667E20 (arm64) CountlyTestApp-iOS.app.dSYM/Contents/Resources/DWARF/CountlyTestApp-iOS
File Upload: While choosing a Symbolication/Mapping File upon uploading the page for iOS, do not forget to zip the dSYM file before uploading. Otherwise, you will not be able to upload a dSYM file in a folder structure.
Notes: Free text optional field.
When everything is filled out, simply click Upload file.
Again, keep in mind you should do this process for every version or build that you would like to symbolicate.
Symbolicating a Crash
After some time has passed, you will start to see new exceptions in your Crashes Overview. If you have uploaded the correct symbols for those versions, then you are ready to move forward with the symbolication process.
To symbolicate a crash, you first have to go to its detailed view by clicking on the crash or on the View button.
As shown below, the detailed crash view will be divided into two parts: the top contains the crash group stack trace, and the bottom contains entries for each specific crash and its circumstances.
When clicking on a specific crash entry, it opens up additional information which contains a Symbolicate toggle button, assuming it's possible to symbolicate the crash (e.g., symbol file is uploaded for the corresponding version). At the top of the crash group section, you may also see the Symbolicate button.
When you click on the Symbolicate button, you should see the Symbolication in progress message. When that process is complete, you should be able to see the symbolicated stack trace.
The current symbolication implementation has some technical limitations, and the top crash group will show a Symbolicate button only after a crash from a newer app version is received. Therefore, if you would like to symbolicate crashes from a version you had before you enabled Symbolication Logs, you will have to scroll down to a specific crash entry at the bottom of the detailed crash view.
FAQs and Troubleshooting
Checking Symbolication Logs
You might come across a situation when trying to symbolicate a crash where you will see something similar to the image below:
This means that there was a problem while trying to symbolicate your crash. To get more information on the problem, either click on the red text or open the Symbolication Logs section of the main Crashes menu.
After the issue which caused the failure has been fixed, you may rerun that symbolication task.
Filtering Rules
The Filtering Rules feature is available only in the Enterprise Edition.
Sometimes, for varying reasons, you may want to block a particular event or session data from being written to the database. The Filtering Rules feature can be handy in such a case.
You may add as many rules as you would like, e.g., based on the IP, country, browser, platform, etc. You may also filter based on sessions or events.
Getting Started
The Filtering Rules feature is enabled by default in the Enterprise Edition and you can find it in the Main Menu > Utilities > Filtering Rules. If you still don’t see it, go to the Sidebar > Management > Feature Management and enable the Filtering Rules toggle.
Filtering Rules Overview
Using Filtering Rules
The Filtering Rules feature View has the below details:
- Filtering Rules list: Each filtering rule in the list can be quickly activated or deactivated using its respective toggle button.
- Table controls: Use them to change the columns shown in the table or to search for particular surveys.
- Filtering Rules menu: You can edit filtering rules as per your needs or delete old ones.
- + Create New Filtering Rule button: Opens the drawer to create a new filtering rule.
Creating a Filtering Rule
Upon clicking the + Create New Filtering Rule button in the main Filtering Rules View, a creation drawer will appear.
Creating a filtering rule in Countly is an easy process:
- Choose Filtering Rules For: Choose whether you would like to filter all requests, request based on session, or request based on events.
- Choose Targeting: You can either block all requests or add a filter.
- Add filtering to define more accurate blocking: You can add filters such as IP Address, hostname, etc. The more filters you use, the more granular and deeper your data will be.
You can keep adding properties by using the + Add Property button
In addition to this if you had selected filtering rules for events, you will need to select your event settings.
- Select from existing events: Choose from the dropdown the event you would like to block.
- Enter event string: Enter string to match the event key you want to block in the input field.