Hide sensitive data

When using autocapture, Heap collects target text information about the element that was interacted with, as well as text data from UI elements further up in an element's ancestry. However, some of these elements might contain sensitive user information, or PII, that needs to be excluded from data capture.

Hiding Sensitive Data on Android

There are three options for hiding sensitive data on Android: Disabling text capture, per-view text redaction, and ignoring interactions for specific views.

Disabling all text capture

When initializing Heap, you have the option to disable text capture for all events that are automatically captured. To do this, set the disableInteractionTextCapture in your options object when calling Heap.startRecording. A similar property is available for disabling capture of all accessibility label text (shown below).

import io.heap.core.Heap
import io.heap.core.Options

Heap.startRecording(
  appContext, 
  "YOUR_ENVIRONMENT_ID", 
  Options(
    disableInteractionTextCapture = true,
    disableInteractionAccessibilityLabelCapture = true
  )
)
import io.heap.core.Heap;
import io.heap.core.Options;

Heap.startRecording(
  appContext, 
  "YOUR_ENVIRONMENT_ID", 
  new Options( // Java uses an overloaded constructor.
		Options.DEFAULT_URI,	// Send data directly to Heap.
    15.0,									// Default upload interval of 15 seconds.
    false,								// Whether to capture advertiser ID. Defaults to false.
    true									// *IMPORTANT* Disable text capture set to true.
  )
);

Redacting text for specific views

If you don't want to disable all text capture for your app, you can take a more targeted approach of only redacting text for specific views in your app that you know might contain sensitive data. When text is redacted for a view, it will still have target text, but the actual text will be replaced with ****. This can be done either in XML or in code, depending on which is most appropriate for your app setup.

If you want to redact text for a view in XML, you can do so by tagging your view with heapRedactText.

<!-- Button clicks are captured but text is redacted. -->
<Button
	android:id="@+id/redact_button"
	android:layout_width="wrap_content"
	android:layout_height="wrap_content"
	android:text="This text is redacted"
	android:tag="heapRedactText" />

Alternatively, if you want to redact text for a view from your Kotlin or Java code, you can do so using ViewAutocaptureSDK.redactText.

import io.heap.autocapture.ViewAutocaptureSDK

val button = findViewById<Button>(R.id.redact_button)
ViewAutocaptureSDK.redactText(button) // Text in this view will be redacted.
import io.heap.autocapture.ViewAutocaptureSDK;

Button button = (Button)findViewById(R.id.redact_button);
ViewAutocaptureSDK.redactText(button); // Text in this view will be redacted.

Ignoring all interactions for specific views

If you find that certain interactions are prone to capturing sensitive data, or that a certain interaction might indicate sensitive information about a user during analysis, you have the option of ignoring all interactions on a per-view basis. Again, this can be done in XML or in code.

If you want to ignore all interactions for a view in XML, you can do so by tagging your view with heapIgnoreInteractions.

<!-- Button clicks are not captured. -->
<Button
	android:id="@+id/ignore_button"
	android:layout_width="wrap_content"
	android:layout_height="wrap_content"
	android:text="Taps on this button are not captured."
	android:tag="heapIgnoreInteractions" />

Alternatively, if you want to flag a view to be ignored from your Kotlin or Java code, you can do so using ViewAutocaptureSDK.ignoreInteractions.

import io.heap.autocapture.ViewAutocaptureSDK

val button = findViewById<Button>(R.id.ignore_button)
ViewAutocaptureSDK.ignoreInteractions(button) // All interactions with this view will be ignored.
import io.heap.autocapture.ViewAutocaptureSDK;

Button button = (Button)findViewById(R.id.ignore_button);
ViewAutocaptureSDK.ignoreInteractions(button); // All interactions with this view will be ignored.

Hiding Sensitive Data on iOS

There are three options for hiding sensitive data on iOS: Disabling the capture of various fields, per-view property redaction, and ignoring events for specific views.

Disabling all text capture

When initializing Heap, you have several options for disabling capture of event properties containing PII:

  • disablePageviewTitleCapture disables capture of pageview titles from navigation and tab items.
  • disableInteractionTextCapture disables capture of user-visible labels from within a view.
  • disableInteractionAccessibilityLabelCapture Disables capture of accessibility labels on views. These labels can be either developer-defined or system generated when a user has accessibility features enabled. It is good practice to use this option when using disableInteractionTextCapture to prevent PII from being captured.

To use these options, pass them into the option dictionary when calling Heap.shared.startRecording.

Heap.shared.startRecording(
  "YOUR_ENVIRONMENT_ID",
  with: [
    .disableInteractionTextCapture: true,
    .disableInteractionAccessibilityLabelCapture: true,
  ]
)
[[Heap sharedInstance]
  startRecording: @"YOUR_ENVIRONMENT_ID"
  withOptions: @{
    HeapOption.disableInteractionTextCapture: @YES,
    HeapOption.disableInteractionAccessibilityLabelCapture: @YES,
  }
];

Redacting text for specific views

If you don't want to disable all text capture for your app, you can take a more targeted approach of only redacting text for specific views and view controllers in your app that you know might contain sensitive data. When text is redacted for a view, it will still have target text, but the actual text will be replaced with ****. This can be done either in Interface Builder or in code, depending on which is most appropriate for your app setup.

For view and view controllers, you can set heapRedactText and heapRedactAccessibilityLabel.

To set these properties in Interface Builder, first select the element you want to redact, then open the Attributes Inspector sidebar. Towards the top, you will see a category called Responder with four options. Xcode unfortunately truncates these so you will need to hover over the title to confirm the name. You can set Heap Redact Text and Heap Redact Accessibility Label to On to redact these fields.

Screenshot of the fields in Attributes Inspector.

In code, you simply need to set heapRedactText and heapRedactAccessibilityLabel on view, view controllers, or other responders to redact those properties.

import HeapIOSAutocapture

open override func viewDidLoad() {
  button.heapReactText = true
  button.heapRedactAccessibilityLabel = true
}
@import HeapIOSAutocapture;

- (void)viewDidLoad
{
  self.button.heapReactText = YES;
  self.button.heapRedactAccessibilityLabel = YES;
}

Redacting pageview titles

There currently isn’t a property for disabling pageview title capture. Instead, you can disable capture by overriding heapPageviewTitle on a specific view controller subclass and returning nil for the title.

import HeapIOSAutocapture

extension PrivateViewController {
    open override var heapPageviewTitle: String? {
        nil
    }
}
@implementation PrivateViewController (Heap)

- (nullable NSString *)heapPageviewTitle
{
  return nil;
}

@end

Ignoring all interactions for specific views

If you find that certain interactions are prone to capturing sensitive data, or that a certain interaction might indicate sensitive information about a user during analysis, you have the option of ignoring all interactions on a per-view basis. Again, this can be done in Interface Builder or in code.

To set these properties in Interface Builder, first select the element you want to redact, then open the Attributes Inspector sidebar. Towards the top, you will see a category called Responder with four options. Xcode unfortunately truncates these so you will need to hover over the title to confirm the name. You can set Heap Ignore Interactions to On to ignore interactions in this view.

In code, you simply need to set heapIgnoreInteractions on view, view controllers, or other responders to redact those properties.

import HeapIOSAutocapture

open override func viewDidLoad() {
  pinContainerView.heapIgnoreInteractions = true
}
@import HeapIOSAutocapture;

- (void)viewDidLoad
{
  self.pinContainerView.heapIgnoreInteractions = YES;
}

Like with the text redaction properties, these properties are recursive. If, for example, you have a view controller containing a custom PIN screen, you could apply heapIgnoreInteractions to the view or view controller to prevent recording individual button taps.

🚧

It is important to note that this property only applies when to interactions that are hosted within the view or view controller. Interactions in pushed or presented view controllers or elements like UIMenu will not be ignored.

Hiding Sensitive Data on React Native

There are two options for hiding sensitive data on React Native: Disabling text capture and configurable per-view capture rules.

Disabling all text capture

When initializing Heap, you have the option to disable text capture for all events that are automatically captured. To do this, set the disableInteractionTextCapture in your options object when calling Heap.startRecording. A similar property is available for disabling capture of all accessibility label text (shown below).

Heap.startRecording(
  "YOUR_ENVIRONMENT_ID",
  {
    disableInteractionTextCapture: true,
    disableInteractionAccessibilityLabelCapture: true,
  }
)
import io.heap.core.Heap;
import io.heap.core.Options;

Heap.startRecording(
  appContext, 
  "YOUR_ENVIRONMENT_ID", 
  new Options( // Java uses an overloaded constructor.
		Options.DEFAULT_URI,	// Send data directly to Heap.
    15.0,									// Default upload interval of 15 seconds.
    false,								// Whether to capture advertiser ID. Defaults to false.
    true									// *IMPORTANT* Disable text capture set to true.
  )
);

Modifying capture for specific views

React Native provides two custom views <HeapIgnore> and <HeapIgnoreText> and a withHeapIgnore higher-order component to restrict some or all event capture in a region.

To see how these are used, consider the following component:

const PinView = (props) => {
  return (
    <View>
      <Button title="1" rounded />
      <Button title="2" rounded />
      ...
    </View>
  );
};

By default, tapping the 1 button will produce events with the hierarchy PinView Button[title=1][rounded=true] and target text of "1".

Below are examples of how to use these components to restrict capture in on that view.

<HeapIgnore>

Wrapping a view with <HeapIgnore> will suppress all events inside the view. For example:

<HeapIgnore>
  <PinView />
</HeapIgnore>

Tapping the buttons in this view will not produce events.

There are 5 props that can be used to expose partial information.

  • allowInteraction - This allows events to be captured with the remaining props determining how much is exposed. Without any other options, the bottom of the hierarchy is the view immediately inside <HeapIgnore>. In the same event from above, the hiearchy would be PinView.
  • allowInnerHierarchy - This allows the full hierarchy to be exposed, but without properties or text capture. In the same event, you would have a hierarchy of PinView Button.
  • allowProps - This allows property capture, but will exclude text-containing properties if the below options are omitted. In the same event, you would have a hierarchy of PinView Button[rounded=true].
  • allowText - This allows text capture. It can be used alongside allowProps to expose text-containing properties.
  • allowAccessibilityLabel - This allows accessibilityLabel capture.

<HeapIgnoreText>

Wrapping a view with <HeapIgnoreText> will capture events but exclude text and accessibility labels from the event. For example:

<HeapIgnoreText>
  <PinView />
</HeapIgnoreText>

Tapping the buttons in this view will produce events but with a hierarchy PinView Button[rounded=true] and no target text. This is equivalent to <HeapIgnore allowInteractions allowInnerHierarchy allowProps>.

withHeapIgnore

withHeapIgnore takes a component and returns a Higher Order Component that wraps it. This component accepts the same arguments but has <HeapIgnore> already applied.

In the below example, PinView is implemented with RedactedButton, a control that wraps Button. It accepts all the same arguments but has the ignore rules built in.

const RedactedButton = withHeapIgnore(Button, { allowInteraction: true });

const PinView = (props) => {
  return (
    <View>
      <RedactedButton title="1" rounded />
      <RedactedButton title="2" rounded />
      ...
    </View>
  );
};