cxReplay - Masking

There may be parts of the app that the client wants to exclude from being recorded. While they can mask and unmask views as desired, the following input views and view controllers are masked automatically:

  • UITextField
  • UITextView
  • UIPicker
  • UIDatePicker
  • UIWebView
  • ABPersonViewController
  • ABPeoplePickerNavigationController
  • ABNewPersonViewController
  • ABContactViewController
  • ABUnknownPersonViewController
  • ABMembersViewController
  • MFMailComposeViewController

There are also views which will always be masked due to security or OS restrictions:

  • MKMapView
  • Secure UITextViews
  • Views that show videos
  • Camera views
  • Live video views (camera previews)

The ForeSee SDK provides methods to allow the client to mask other views or unmask those that have been automatically masked on a view by view basis. The most common use case is to override the viewDidLoad: method in a UIViewController and register particular views for masking. Example:

- (void)viewDidLoad {
    // Assuming self.nameLabel is an outlet to a view
    [ForeSee maskView:self.nameLabel];
    
    // Assuming self.webView is an outlet to a view
    [ForeSee unmaskView:self.webView];
}

Any subclass of UIView can be masked. If an instance of UITextField, UITextView, or UIWebView is registered to be masked, the keyboard is also masked automatically when visible.

Web Views

Due to the complex nature of web views, they are completely masked by default. If the client would like to capture web views in replays, they must first unmask the webview using the following code:

  [ForeSee unmaskView:yourWebView];  

Once unmasked, web views present a particular challenge to the capture system and masking can be unreliable during some zoom operations. It is therefore important that any web view which contains masked or auto-masked items must have zooming disabled to avoid revealing personal data in the replay. This can be done in the app code…

  // Assuming self.webView is an outlet to a UIWebView
  self.webView.scalesPageToFit = NO;

Or by setting the meta data in the HTML of the page:

  <meta name="viewport" content="initial-scale=1, user-scalable=yes"/>

It is not necessary to disable zooming on pages which do not contain masked views.

Like native views, all input fields within an unmasked webview that may contain personal information are automatically masked. To mask extra areas or unmask views which have been automatically masked, use one of the following methods:

CSS Selectors

This is the recommended way to handle masking and unmasking since it is not necessary to alter the code of the web page. Instead, CSS selectors can be used in the app configuration to identify areas – or sets of areas – which require masking or unmasking. For example, [name=your_element_name] selects all elements with the name “your_element_name”.

Selectors can be applied to all webpages displayed within the app, or restricted to a certain page or set of pages. To implement CSS selectors, the client can add a file called foresee_masking.json to the project and insert the selectors according to the following format:

{
  "webview_masking": {
    "unmasked":
    {
      "http://yourdomain.com": ".search",
      "": ".public"
    },
    "masked":
    {
      "http://yourdomain.com/index.html": "[name=credit_card_number]",
      "billing": ".secret"
    }
  }
}

Masks added or removed in this way are only applied to a page if its URL contains the URL snippet specified in the configuration; the client can be as specific or general as desired by including as much or as little of the URL as necessary. It is also possible to add selectors to apply to all pages by leaving the URL string empty.

The configuration in the example above ensures that any elements with the class ‘search’ is unmasked in any page within the domain “yourdomain.com”, as is any element of class ‘public’ on any page. Masks are also added to any elements named ‘credit_card_number’ on the page “http://yourdomain.com/index.html” and all elements with the class ‘secret’ on any page where “billing” appears in the URL.

CSS Classes

This method requires the code of the webpage in question to be modified to apply ForeSee masking classes to the elements requiring masking and unmasking. Since this method is governed by the CSS classes in the webpage code, the app code does not need to be changed, making this method useful for changing the masking criteria after an app has been released.

To mask or unmask an element, the client must apply the fs-masked or fs-unmasked class to the element as follows:

<div id="your_div" class="your_class fs-masked">

Web View Alerts

Alerts launched using the javascript functions alert(), confirm(), or prompt() can be masked on a per-webview basis. To mask all alerts from a particular UIWebView, use the following call:

  [ForeSee maskAlertsForWebView:yourWebView];

The process can be reversed at any time with immediate effect by calling the following function:

  [ForeSee unmaskAlertsForWebView:yourWebView];

Gestures

If the user is inputting data into a masked ‘UITextField’ or ‘UITextView’, all keyboard gestures are automatically masked. When entering data into a ‘UIWebView’, keyboard gestures are masked if there are any masked views anywhere on the page being displayed.

Debugging Your Masking Setup

From version 3.4 onwards, it is possible to review your masking setup in real time by observing the masks in your app as you use it. To enable this feature, add the following command just before you start the ForeSee SDK:

[ForeSee setMaskingDebugEnabled:YES];

This feature highlights all masked areas using a translucent red area. Most interactions with your app should continue as normal, but there are a couple of points to bear in mind when using this ‘live masking’:

  • This is not intended as a tool to debug the timing of masks – only to confirm that the right UI items are being selected as masked and unmasked.
  • Live masking will only give a precise reflection of the final masks that will appear in the replay when the view is static. Although the live masks represent exactly what will be masked, they will with a different timing to the final masking system, so although some items may appear unmasked during live masking, final masking will not contain these skipped masks.
  • Once you have confirmed that the correct items are masked, it is a good idea to check the final replays to make doubly sure masks are being applied correctly.
  • Live masking will interfere with some UI elements, often producing dramatic reductions in the user experience. We are working to improve this, but in the meantime it’s important to note that these issues will only happen when debug masking has been enabled at least once since the app was started. The views currently known to be affected are:
    • Address Book/Contact pages
    • Privacy prompts, eg. photo album permissions

Other articles in this section:

  1. cxReplay Overview
  2. Sessions
  3. Paging
  4. Masking (current article)
  5. Performance
  6. Limitations