Who can use this feature?
- Available with Mobile add-on.
- Requires an admin role to configure.
The rules specified below apply only to the fully-native portion of applications, and not to any HTML running within WebViews (Android), UIWebView (iOS) or WKWebView (iOS). For privacy management in the HTML portion of hybrid apps, please see the Fullstory exclusion reference.
Overview
The privacy rules for mobile applications are based on the same selectors used for web applications. For users familiar with CSS syntax, these rules will look familiar.
See the Fullstory exclusion reference and the MDN CSS selector reference for additional background.
When the Fullstory for Mobile Apps instrumentation SDK starts up, it immediately fetches the latest privacy rules from the server. No information is captured before these privacy rules have been fetched.
Privacy rules fall under one of three types:
- Exclusion: excluded views and all child views are removed from the playback and replaced by a striped box. No information about the contents of the view will leave the device, with the exception of the bounds of the view box. In addition, no tap or swipe events will be visible within the bounds of an excluded element.
- Masking: masked views and all children are maintained and available at playback, but all text and image content within a masked view is omitted.
- Unmasking: an unmasking rule returns an element to its fully-visible state, including all text and image information contained within.
Priority of Privacy Rules
If two rules match the same element, then the more conservative (i.e., mask or exclude) one will win.
If no rules match an element, the element will inherit masking state from its parent.
If an element matches an exclude rule, the element and all of its children are replaced with an exclusion placeholder and no further rule matching takes place.
Example of Masking/Unmasking
Masked text elements appear as a rectangle covering the bounds of the text information in the application. The text itself does not leave the client device, only the information describing the approximate width and height of the text. Masked image elements are represented by a dominant color from the image.
Example of Masking vs Exclusion
Excluded elements appear as a diagonal stripe pattern, in contrast to the bar used to represent a masked text area.
Masking and Exclusion Guarantees
Fullstory guarantees that none of an excluded view’s contents, nor any of the contents of any child views, will leave the device. The hash line pattern represents the original bounds of the excluded elements.
The text and image contents of a masked element are guaranteed not to leave the device. The instrumentation library instead sends the original bounds of masked text, and a dominant color for any images. Any drawing commands alongside the text and images are sent as-is, however.
Limitations of Masking and Exclusions
Masking and exclusions are powerful tools, but there are a small number of circumstances where the information remaining after masking/exclusion may impact privacy aspects of an application.
- Limitation: Numeric fields where the magnitude of the value may be considered sensitive may have that magnitude revealed by the size of the masked or excluded view box for that view. For example, someone viewing a session may be able to tell $1,000 from $1,000,000 by observing the size of a box.
- Mitigation: An exclusion rule may be applied at a higher level than the view containing the numeric value. The application may also be redesigned such that the view is always the same size regardless of the numeric value.
- Limitation: Applications with interfaces that mimic PIN entry systems may reveal the PIN through the location of tap events, even though the interface is masked by default.
- Mitigation: Interfaces where click events may reveal information based on the location of the click should be fully excluded. Excluding an element will remove interaction information from the data capture stream.
- Limitation: Applications with custom-drawn views where position may reveal information may still contain sensitive information, even when masked. For example, a slider control where the values at given positions are well-known may reveal the value of that slider field.
- Mitigation: If non-textual, non-image information inside a view may reveal information, that view should be excluded. This will permanently remove all drawing commands - not just text and images.
Virtual Attributes
This section assumes that the reader has basic familiarity with HTML and CSS.
To simplify management of privacy for mobile applications and to be more familiar with individuals who have worked with Fullstory for the web, Fullstory for Mobile Apps instrumentation creates virtual HTML-like elements for native Android or iOS views for the purposes of privacy management, funnel definition, and searches.
In a standard HTML document, an element might appear like so:
<div id="my-id" data-test="some-test-id">
CSS selectors can be used to match that element. Examples of selectors that would match:
div#my-id // # represents the “id" selector
div[data-test="some-test-id"] // [] represents an attribute selector
Tag Name
The virtual element’s tag name is mapped from the class name of the view in Android or iOS.
iOS:
For example, a UITextView in an iOS app creates a virtual element with a tag name that looks like so:
<UITextView …
Android:
For an Android TextView, the instrumentation creates a virtual element with a tag name of “TextView". Also note that because Android classes include the Java package of the view in an attribute named “package":
<TextView package="android.widget" …
The selector rules that would match the above views are:
TextView[package="android.widget"]
UITextView
ID
iOS:
The accessibility ID attribute is mapped to the virtual element’s ID attribute. For example, a UITextView with an accessibilityIdentifier of “text" maps to the following virtual element:
<UITextView id="text" …
Android:
On Android, the View’s text ID is mapped to a virtual ID attribute. For example:
<TextView android:id="@+id/text"
android:text="Hello, I am a TextView" />
The virtual element generated for the above view would be:
<TextView package="android.widget" id="text" …
The selector rule that would match both iOS and Android views would be:
#text
Attributes
Below is a summary of all mapped virtual attributes:
Virtual Attribute |
Android | iOS |
Element’s tag |
View.getClass() |
Objective-C class name of UIView |
id |
View.getId() |
[UIView accessibilityIdentifier] |
tag |
View.getTag() |
[UIView tag] |
package |
View’s Java package |
|
type |
TextView.getInputType() |
|
href |
TextView.getUrls() |
|
controller |
Class of [UIView nextResponder], if this nextResponder is a UIViewController |
|
label |
[UIView accessibilityLabel] |
|
restoration_id |
[UIView restorationIdentifier] |
|
storyboard |
[[UIView storyboard] name] |
Techniques for Matching Elements
FS.setAttribute
In version 0.99.10 of the Fullstory for Mobile Apps instrumentation SDK, the FS.setAttribute() API is available to create virtual attributes of any kind on native views.
This API is only available to the native parts of the application, and can be used like so:
FS.setAttribute(myView, "my-attribute", "my-attribute-value") FS.addClass(myView, "my-class")
Assuming that myView is an Android TextView, this would add the attribute “my-attribute" with the value “my-attribute-value" and the class “my-class”, resulting in a virtual element that appears as:
<TextView class="my-class" my-attribute="my-attribute-value" ...
The APIs available map to APIs available for HTML-based pages:
Web |
Android |
iOS |
Element.setAttribute |
FS.setAttribute |
[FS setAttribute] |
Element.removeAttribute |
FS.removeAttribute |
[FS removeAttribute] |
Element.classList.add |
FS.addClass |
[FS addClass] |
Element.classList.remove |
FS.removeClass |
[FS removeClass] |
Element.className = "" |
FS.removeAllClasses |
[FS removeAllClasses] |
n/a |
FS.setTagName |
[FS setTagName] |
Custom attributes may be used for privacy purposes within the Fullstory ecosystem and in the future will be available for use in search and funnels.
Programmatic Privacy Rules
To control privacy settings via code, native mobile applications can make use of FS.addClass like so:
iOS:
// The password field should be entirely excluded
[FS addClass:myPasswordView className:@"fs-exclude"];
// The hint label field does not contain PII, so it should always be unmasked [FS addClass:myPasswordHintLabelView className:@"fs-unmask"];
Android:
// The password field should be entirely excluded
FS.addClass(myPasswordView, "fs-exclude");
// The hint label field does not contain PII, so it should always be unmasked
FS.addClass(myPasswordHintLabelView, "fs-unmask");
New in 1.4.0 - You can also specify FS.class in your XML layouts. Here's an example of what that looks like:
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:fullstory="http://schemas.android.com/apk/res-auto"
android:id="@+id/rootview"
>
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/title_tv"
fullstory:fs_class="fs-unmask"
First you need to add the Fullstory XML namespace to the root view in the layout. Then you can add the fs_class attribute to the view you want to mask or unmask.
Additionally, you can add your own ‘CSS classes’ to make it easier to search in Fullstory for matching elements.
-
To add more than one class, use comma separated values
-
fullstory:fs_class=“fs-mask,checkout_form_item”
-
Some notes on using Fullstory XML layout attributes on Android.
- If you’re seeing a linting issue like “Unexpected prefix ‘fullstory’ on TextView”, make sure to use the AppCompat versions of views, as old Android views didn’t support custom namespaces.
- Views must have an ID for this attribute to work.
Pre-configured Privacy Classes
The complete set of pre-configured classes that may be applied to control privacy are:
Type |
Always applied * |
Consent-modified ** |
Excluded elements |
fs-exclude |
fs-exclude-without-consent |
Masked elements |
fs-mask |
fs-mask-without-consent |
Unmasked elements |
fs-unmask |
fs-unmask-with-consent |
* If this class is applied, the element will be excluded/masked/unmasked unconditionally
** If this class is applied and FS.consent is called with the appropriate value, the element will be excluded/masked/unmasked
The mobile SDKs provide constants for each of these classes, as well as helper methods to apply each of the built-in privacy rules.
See https://developer.fullstory.com/add-class for a complete list.
Advanced Attribute Matching
As with CSS, advanced match rules can be used to match more than one possible attribute value. See the W3Schools CSS selector reference for background.
CSS Attribute Match |
Description |
Example Matches |
view[attribute] |
Matches a view with the given attribute present |
<view attribute> |
view[attribute=value] |
Matches a view with the given attribute being exactly “value" |
<view attribute="value"> |
view[attribute*=value] |
Matches a view where the attribute contains the substring “value" |
<view attribute="abc-value-def"> |
view[attribute^=value] |
Matches a view where the attribute starts with “value" |
<view attribute="value-abc"> |
view[attribute$=value] |
Matches a view where the attribute ends with “value" |
<view attribute="abc-value"> |
view[attribute~=value] |
Matches a view where the attribute contains the word “value" with whitespace surrounding it |
<view attribute="abc value def"> |
React Native
The virtual elements created for React Native applications tend to be difficult to match as most appear to be of the generic form of RCTView/RCTTextView on the iOS platform, or ReactViewGroup/ReactTextView on the Android platform.
React Native provides a testID prop that can be useful as it maps to native properties that are already mapped to virtual attributes. On iOS, the testID prop maps to accessibilityIdentifier, while on Android testID maps to the view’s tag.
Specifying testID="myElement" on a React text element would then generate the following two virtual elements on iOS and Android, respectively:
<RCTView id="myElement">
<ReactTextView tag="myElement">
At this time there is no way to match both Android and iOS from a single selector, but the following two rules will correctly match this React view:
#myElement
*[tag="myElement"]
SwiftUI
For customers who are already familiar with using Fullstory on iOS with UIKit or React Native apps, Fullstory’s SwiftUI support is a bit different. To learn more, read our article What's Different in Fullstory for SwiftUI? Or the how-to companion article, Integrating Fullstory into a SwiftUI App.
Supported Selector Reference
The selector rules supported by Fullstory’s for Mobile Apps SDK are:
#idselectors .classselectors parent>child tagname tagname[attribute] tagname[attribute=foo] tagname[attribute*=value] tagname[attribute^=value] tagname[attribute$=value] tagname[attribute~=value]