While in open beta, Heap for React Native may undergo significant changes as we develop new capabilities.
Overview
Use this guide for complete steps to install Heap on React Native apps. For web installation instructions, see our web installation guide.
Please review the following list of requirements and known limitations to ensure your project is set up for this installation process.
For notes on the latest SDK versions, see our React Native changelog.
Requirements and Known Limitations
iOS
- iOS apps will capture both React Native autocaptured events, as well as events captured by the Heap iOS integration
- The Event Visualizer is not yet available for React Native iOS applications
Android
If youâre running React Native SDK version 0.9.0 and above, you can define React Native events via the Android Event Visualizer.
- Android apps do not currently receive native events, such as Fragment Transitions
Expo Framework
Our support for Expo depends on which workflow you use:
- If you are using the bare workflow, and you are able to complete each step of these installation instructions, it should be supported by Heap â this can vary based on your project file setup
- If you are using the managed workflow, in which case there are no iOS or Android folders in your project, or if the app is not âejectedâ, it is not supported by Heap
Installation
To install Heap for React Native:
-
From the command line, install the NPM module by running
npm install --save "@heap/react-native-heap"
-
For autocapture, add the following plugins to your
.babelrc
configuration:
{
"plugins": [
"add-react-displayname",
"./node_modules/@heap/react-native-heap/instrumentor/src/index.js"
]
}
-
For additional information on how to capture component props, see the section below on Prop Capture
-
For React Navigation versions 5 and above, to autocapture screenviews, wrap
Heap.withReactNavigationAutotrack()
around theNavigationContainer
:
const HeapNavigationContainer = Heap.withReactNavigationAutotrack(
NavigationContainer
);
For React Navigation versions below 5, wrap the AppContainer (the result of a call to React Navigationâs createAppContainer()
method) with Heap.withReactNavigationAutotrack()
import Heap from '@heap/react-native-heap';
let AppNavigator = createStackNavigator(
{
LoginView: { screen: LoginView },
MainMenu: { screen: MainMenu },
SearchView: { screen: SearchView },
ProductView: { screen: ProductView }
},
{
initialRouteName: 'LoginView'
}
)
let App = Heap.withReactNavigationAutotrack(createAppContainer(AppNavigator));
iOS
When installing React Native on iOS, we recommend using heapignore
to ignore native iOS events that may include sensitive user data, or that are not relevant to your business needs (for example, things like RCTTouchHandler
.) You can do this by adding the following line to the didFinishLaunchingWithOptions
function in your AppDelegate.m
file:
[rootView setValue:@true forKey:@"heapIgnore"];
Note that this will suppress all native iOS events within the root view of the react native app, and not just remove specific elements.
React Native >=0.60 (With Autolinking)
Run the following:
pod repo update
pod install
React Native <0.60 (Without Autolinking)
iOS Using CocoaPods
- If you donât have a Podfile in the ios folder of your React Native project, follow this guide to create one
- Add the following to your Podfile:
pod "react-native-heap", path: "../node_modules/@heap/react-native-heap"
- Then run:
pod repo update
pod install
iOS Without CocoaPods
All terminal commands assume you are in the top-level directory of your React Native project.
- Locate the Xcode project for RNHeap:
open node_modules/@heap/react-native-heap/ios
. You should see a Finder window containing theRNHeap.xcodeproj
file. - Open the Xcode project for your native app, in the
ios
directory of your project. - Drag the
RNHeap.xcodeproj
file from the Finder window into the âLibrariesâ group of your Xcode project. - Select your project name in the Xcode project navigator. Select the âBuild Phasesâ tab for your appâs target.
- Expand the build phase called âLink Binary With Librariesâ. In the project navigator on the left, expand the
RNHeap.xcodeproj
entry, and findlibRNHeap.a
in the âProductsâ group. The icon forlibRNHeap.a
should look like a little building with columns. - Drag the
libRNHeap.a
file into the list of other libraries to be linked. - Expand the build phase called âCopy Bundle Resourcesâ. In the project navigator on the left, under the expanded
RNHeap.xcodeproj
entry, findHeapSettings.bundle
. - Drag the
HeapSettings.bundle
file into the list of bundle resources to be copied.
When completing the steps above, please note the following;
- Steps 7-8 are only necessary when using automatic initialization, not when using manual initialization
- Use of
react-native
link is not currently supported
Android
React Native >=0.60 (With Autolinking)
With React Native autolinking, Heap should work on Android without any changes needed to the native Android code.
React Native <0.60 (Without Autolinking)
In some cases, simply running react-native
link will correctly set up the instrumentor on Android. However, if you encounter any issues (either with the command itself or at compile-time/run-time), you should revert any changes made by react-native
link and instead try the following steps.
- Add the following to your
settings.gradle
:
include ':react-native-heap'
project(':react-native-heap').projectDir =
new File(rootProject.projectDir, '../node_modules/@heap/react-native-heap/android')
-
Then add the following to
app/build.gradle:implementation project(':react-native-heap')
-
Import the package and add it to your appâs
MainApplication
:
@Override
import com.heapanalytics.reactnative.RNHeapLibraryPackage;
...
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new RNHeapLibraryPackage()
);
}
Configuration
Automatic Initialization
As of version 0.4.0 of this library, we recommend auto-initialization over manually setting your Heap app ID within app code. The manual approach is still supported, however: see the Manual Initialization section below.
The library needs to be initialized so events are sent to the right app ID. Place a heap.config.json
file at the root of your applicationâs repository with this structure, substituting your own app IDs.
{
"default": {
"heapAutoInit": true
},
"dev": {
"heapAutoInit": true,
"heapAppId": "12"
},
"prod": {
"heapAppId": "11",
"heapAutoInit": true
}
}
- Note that different app IDs can be set for development and production. Heap can also be enabled/disabled on a per-environment basis. Values in
default
are used if a key is missing in either dev or prod. - The library distinguishes between dev and prod builds using the DEV variable.
If you are seeing runtime warnings at startup mentioning Heap: Could not find BuildConfig
, add the following line to the resources section of res/values/strings.xml
:
<string name="com.heapanalytics.android.buildConfigPkgName">com.your_package_name</string>
and replace com.your_package_name
with the package name from the manifest tag in AndroidManifest.xml
.
Manual Initialization
If youâd like finer-grained control over when the Heap library initializes, call Heap.setAppId
with an app ID. (Most users wonât need to do this.)
import Heap from '@heap/react-native-heap';
Heap.setAppId('YOUR_APP_ID');
In addition, find the MainActivity.java
file, which is React Nativeâs Android-specific entry point. This file is typically present in a subfolder of android/app/src/main/java/
. Add the following imports:
import com.heapanalytics.reactnative.RNHeap;
import android.os.Bundle;
Next, add an onCreate
method containing the following. If an onCreate
method already exists, simply add the RNHeap.init
line to it.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
RNHeap.init(getApplicationContext(), "<YOUR_APP_ID>");
}
Ignoring Sensitive Data and PII
On React Native, autocaptured data will include interactions with certain types of components, as well as capturing target text from components if there is any to capture. Additionally, commonly-used props for popular UI libraries, like React Native Elements or NativeBase, may also be captured as a part of the component hierarchy event property. The result is that some care is needed when dealing with components that contain sensitive information or other PII.
The Heap for React Native SDK (version 0.4.0 and greater) offers several methods for ensuring that PII is not sent from a React Native app to Heap, using React components that may be used within JSX code or via higher-order components.
Target Text Autocapture toggle
Admins can control the capture of sensitive information that lives on the target text of elements by turning on the Target Text Autocapture toggle on the Account > Manage > Privacy & Security page.


Please note that disabling target text entirely might make defining events more difficult. Also, if you have this setting enabled while using the APIs listed below, then the most privacy-conscious setting will win.
HeapIgnore and HeapIgnoreTargetText Functional Components
The Heap for React Native SDK provides two convenient functional components for restricting the data that is autocaptured by Heap.
- The
HeapIgnore
component is the most restrictive component, and can be used to stop Heap from capturing any events below the ignored component in the hierarchy.
For example, consider a component that has an extremely sensitive piece of information in some button text:
import React, { Component } from 'react';
class MySensitiveScreen extends Component {
render() {
const safeProp = this.props.profile.randomUuid;
const superSensitiveProp = this.props.profile.creditCardNum;
const { styles } = this.props.styles;
return (
<View style={styles.container}>
<TouchableHighlight onPress={this._onPressButton} underlayColor="white">
<View style={styles.button}>
<Text style={styles.buttonText}>{superSensitiveProp}</Text>
</View>
</TouchableHighlight>
<TouchableHighlight onPress={this._onPressButton} underlayColor="white">
<View style={styles.button}>
<Text style={styles.buttonText}>{safeProp}</Text>
</View>
</TouchableHighlight>
</View>
);
}
}
export default MySensitiveScreen;
As written, Heap would capture any interactions with both of the buttons and set Target Text event properties with the content of the Text components. We can re-write this component to use HeapIgnore
:
import React, { Component } from 'react';
import { HeapIgnore } from '@heap/react-native-heap';
class MySensitiveScreen extends Component {
render() {
const safeProp = this.props.profile.randomUuid;
const superSensitiveProp = this.props.profile.creditCardNum;
const { styles } = this.props.styles;
return (
<View style={styles.container}>
<HeapIgnore>
<TouchableHighlight onPress={this._onPressButton} underlayColor="white">
<View style={styles.button}>
<Text style={styles.buttonText}>{superSensitiveProp}</Text>
</View>
</TouchableHighlight>
</HeapIgnore>
<TouchableHighlight onPress={this._onPressButton} underlayColor="white">
<View style={styles.button}>
<Text style={styles.buttonText}>{safeProp}</Text>
</View>
</TouchableHighlight>
</View>
);
}
}
export default MySensitiveScreen;
By wrapping the TouchableHighlight
that contains the button with sensitive text in a HeapIgnore
component, you can prevent Heap from capturing any interactions from the button. Interactions with the other button, which has safe target text, will still be sent to Heap. The HeapIgnore
component can be used to ignore events very broadly, as well as very specifically. For example, wrapping the entire App component in HeapIgnore
would ignore all autocaptured events from the entire application. For more specific use cases, the HeapIgnore
component can be used to ignore events from a specific button.
- Sometimes, however, it is important to be able to capture the fact that a user interacted with a button or other component, and you just want to ensure that the target text itself is not captured.
In these cases, the HeapIgnoreTargetText
component is extremely useful:
import React, { Component } from 'react';
import { HeapIgnoreTargetText } from '@heap/react-native-heap';
class MySensitiveScreen extends Component {
render() {
const safeProp = this.props.profile.randomUuid;
const superSensitiveProp = this.props.profile.creditCardNum;
const { styles } = this.props.styles;
return (
<View style={styles.container}>
<HeapIgnoreTargetText>
<TouchableHighlight onPress={this._onPressButton} underlayColor="white">
<View style={styles.button}>
<Text style={styles.buttonText}>{superSensitiveProp}</Text>
</View>
</TouchableHighlight>
</HeapIgnoreTargetText>
<TouchableHighlight onPress={this._onPressButton} underlayColor="white">
<View style={styles.button}>
<Text style={styles.buttonText}>{safeProp}</Text>
</View>
</TouchableHighlight>
</View>
);
}
}
export default MySensitiveScreen;
In this version of our example component, Heap will capture all of the touchableHandlePress
events that occur for both buttons. For the button with the safeProp
text, events will contain a Target Text event property with the value of safeProp
. However, for the button with the sensitive text, the Target Text event property will be suppressed, and no PII or sensitive information will be captured.
NOTE: HeapIgnoreTargetText still sends through component properties that have been configured for capture. For example, <Button title={sensitiveProp}/>
would still capture the title property as a part of the autocaptured event.
Suppressing Target Text is an extremely useful way to avoid sending PII, but can result in the elimination of important metadata for defining virtual events. In cases where some additional metadata is required for specifically defining an event, it is recommended to add a testID
property, which will be captured automatically by Heap. These testIDs
are typically used for automated testing using tools like Detox or Appium.
HeapIgnore Higher-Order Component
In some cases, it is easier to use a Higher-Order Component (HOC) for applying ignore functionality. For example, if you wanted to ignore all interactions for all instances of a component, but always contain sensitive data, HOCs can be very useful. As an example, we might have a button that frequently contains sensitive information as its text. We can ensure that those interactions will not be captured by exporting an ignored button using the HOC.
import React, { Component } from 'react';
import Heap from '@heap/react-native-heap';
class SensitiveButton extends Component {
render() {
const safeProp = this.props.profile.randomUuid;
const superSensitiveProp = this.props.profile.creditCardNum;
const { styles } = this.props.styles;
return (
<TouchableHighlight onPress={this._onPressButton} underlayColor="white">
<View style={styles.button}>
<Text style={styles.buttonText}>{superSensitiveProp}</Text>
</View>
</TouchableHighlight>
);
}
}
const IgnoredSensitiveButton = Heap.withHeapIgnore(SensitiveButton);
export default IgnoredSensitiveButton;
Then we can use this in other locations within the app. Using our previous example:
import React, { Component } from 'react';
import { IgnoredSensitiveButton } from './components/SensitiveButton'
import { Heap } from '@heap/react-native-heap';
class MySensitiveScreen extends Component {
render() {
const { styles } = this.props.styles;
return (
<View style={styles.container}>
<IgnoredSensitiveButton />
<IgnoredSensitiveButton />
</View>
);
}
}
export default MySensitiveScreen;
In this case, the button with sensitive data can be re-used throughout the app, but Heap will ignore all interactions with those buttons, due to the use of the HeapIgnore HOC.
For more information on Heap's data privacy options, see How do I use Heap to comply with data privacy legislation?
Troubleshooting
The react-native-heap module cannot be built as a dynamically linked framework. If your app uses use_frameworks!
in your Podfile, you will need to add an additional pre-install step to the Podfile:
pre_install do |installer|
pod = installer.pod_targets.find { |p| p.name == 'react-native-heap'}
def pod.static_framework?
true
end
end
Manual Tracking Usage Examples
The following code snippet is an example of how to set up manual tracking:
// Import Heap.
import Heap from '@heap/react-native-heap';
// Identify your user.
Heap.identify('123456');
Heap.addUserProperties({ name: 'John', age: 54 });
// Add event properties (these persist across sessions).
Heap.addEventProperties({ isLoggedIn: true });
// You can remove a specific property or clear everything.
Heap.removeEventProperty('isLoggedIn');
Heap.clearEventProperties();
// To track an event, use:
Heap.track('signed-up', { isPaid: true, amount: 20 });
Autocaptured Events
Native Events (iOS Only)
In addition to React Native-specific events, the React Native Heap integration autocaptures events from the native iOS library. Native Android events, such as fragment transitions, are not currently captured.
Screenviews
Heap captures screenviews through integrations with popular navigation frameworks. Currently, only React Navigation 3.0+ is supported.
Screenviews are not captured by default, and autocapture can be activated as follows:
React Navigation Versions 5 and above
Wrap Heap.withReactNavigationAutotrack() around the NavigationContainer:
const HeapNavigationContainer = Heap.withReactNavigationAutotrack(
NavigationContainer
);
React Navigation Versions below 5
Wrap the React Navigation AppContainer with Heap.withReactNavigationAutotrack()
. For example:
import Heap from '@heap/react-native-heap';
let AppNavigator = createStackNavigator(
{
LoginView: { screen: LoginView },
MainMenu: { screen: MainMenu },
SearchView: { screen: SearchView },
ProductView: { screen: ProductView }
},
{
initialRouteName: 'LoginView'
}
)
let App = Heap.withReactNavigationAutotrack(createAppContainer(AppNavigator));
React Native-Specific Captured Properties:
- Type: For React Navigation, the event type will be
reactNavigationScreenview
. - path: The
path
property will contain the the name of the view as defined with React Navigation. Example:LoginView
. - type: The type of screenview â for standard navigation operations, this will be
Navigation/NAVIGATE
. This property will not be defined on events if the screen was viewed as the initial route.
Touchables
Heap will capture touches on any component that is backed by any of the Touchable
components, like TouchableHighlight
, TouchableOpacity
, etc. This will effectively capture touch interactions with a wide variety of components, but will not distinguish between gestures on those components. Heap captures the component hierarchy as a part of this event, which should enable basic specification of events.
React Native-Specific Captured Properties:
- Type: For Touchables, the event type will be
TouchableHandlePress
. - touchableHierarchy: This contains the component hierarchy of associated with the event. Example:
AppContainer;|App;|Provider;|Connect(RouterComponent);|RouterComponent;|Router;|App;|NavigationContainer;|KeyboardAwareNavigator;|Navigator;|StackView;|Transitioner;|withOrientation;|StackViewLayout;|ScreenContainer;|Container;|Card;|Screen;|AnimatedComponent;|SceneView;|NavigationContainer;|Navigator;|_default;|NavigationContainer;|KeyboardAwareNavigator;|Navigator;|StackView;|Transitioner;|withOrientation;|StackViewLayout;|ScreenContainer;|Container;|Card;|Screen;|AnimatedComponent;|SceneView;|NavigationContainer;|KeyboardAwareNavigator;|Navigator;|StackView;|Transitioner;|withOrientation;|StackViewLayout;|ScreenContainer;|Container;|Card;|Screen;|AnimatedComponent;|SceneView;|Wrapped;|Connect(ProductScreen);|ProductScreen;|KeyboardView;|KeyboardAvoidingView;|ScrollView;|Button;[title=Save];|TouchableOpacity;|
- touchState: Touch state of the component at the time of the event. This is a string representation of an internal state enumeration. Example:
RESPONDER_ACTIVE_PRESS_IN
- targetText: If there is a textual element to the component being touched, Heap will capture that associated text. Heap attempts to infer the target text, but may not always be able to extract it automatically. Currently, the text must be a descendent of the
Touchable
component.
Component Props
Heap attempts to autocapture commonly used props for standard components, as well as popular component libraries and UI kits. For example, most React Native apps will have a component called Button
, which often has a prop called title
. When a Touchable event is triggered from a Button
, the title
prop will be automatically included in the event by augmenting the touchbleHierarchy
event property.
For example, a Button
component labeled with the text âSaveâ would result in a touchableHierarchy
event prop like this (note Button;[title=Save];
):
AppContainer;|App;|Provider;|Connect(RouterComponent);|RouterComponent;|Router;|App;|NavigationContainer;|KeyboardAwareNavigator;|Navigator;|StackView;|Transitioner;|withOrientation;|StackViewLayout;|ScreenContainer;|Container;|Card;|Screen;|AnimatedComponent;|SceneView;|NavigationContainer;|Navigator;|_default;|NavigationContainer;|KeyboardAwareNavigator;|Navigator;|StackView;|Transitioner;|withOrientation;|StackViewLayout;|ScreenContainer;|Container;|Card;|Screen;|AnimatedComponent;|SceneView;|NavigationContainer;|KeyboardAwareNavigator;|Navigator;|StackView;|Transitioner;|withOrientation;|StackViewLayout;|ScreenContainer;|Container;|Card;|Screen;|AnimatedComponent;|SceneView;|Wrapped;|Connect(ProductScreen);|ProductScreen;|KeyboardView;|KeyboardAvoidingView;|ScrollView;|Button;[title=Save];|TouchableOpacity;|
If an event does not have sufficient specificity between autocaptured props and component hierarchies, it may be necessary to configure the prop capture further in the app code. For more details, see the Configuring Prop Capture section just below this one.
Configuring Prop Capture
Heap comes configured with an initial set of prop-capture configurations for commonly-used components, and will eventually support common props for popular UI kits like NativeBase and React Native Elements. If capture of a non-default property is required, this can be achieved by adding a small piece of configuration code to the app. Prop capture configurations can be assigned to both stateless functional and stateful components.
In order to achieve this, Heap will check for a specially-named heapOptions
property that contains a set of properties to include or exclude. The structure of the property is as follows:
heapOptions = {
eventProps: {
include: [ '<inc_prop_1>', '<inc_prop_2>', ..., '<inc_prop_n>' ],
exclude: [ '<exc_prop_1>', '<exc_prop_2>', ..., '<exc_prop_n>' ],
}
}
Properties in the include
list will be included in the event. Properties in the exclude
list will be explicitly excluded if they would have been otherwise included
by either the include list or a built-in prop configuration.
Stateless, Functional Component Example:
import React from 'react';
import { Text, TouchableOpacity, View } from 'react-native';
const ProductItem = ({name, price, onPress}) => {
return (
<TouchableOpacity onPress={onPress}>
<View>
<Text>{name}</Text>
<Text>{price}</Text>
</View>
</TouchableOpacity>
);
}
ProductItem.heapOptions = {
eventProps : { include: [ 'name', 'price' ] }
};
export { ProductItem };
Stateful Component Example
import React, { Component } from 'react';
import { Text, TouchableOpacity, View } from 'react-native';
export default class ProductItem extends Component {
heapOptions = {
eventProps : { include: [ 'name', 'price' ] }
};
render() {
return (
<TouchableOpacity onPress={onPress}>
<View>
<Text>{name}</Text>
<Text>{price}</Text>
</View>
</TouchableOpacity>
);
}
}
Use of a custom prop configuration will result in additional props being captured within the touchableHierarchy
event property (note ProductItem;[name=Foo];[price=$1.00]
):
AppContainer;|App;|Provider;|Connect(RouterComponent);|RouterComponent;|Router;|App;|NavigationContainer;|KeyboardAwareNavigator;|Navigator;|StackView;|Transitioner;|withOrientation;|StackViewLayout;|ScreenContainer;|Container;|Card;|Screen;|AnimatedComponent;|SceneView;|NavigationContainer;|Navigator;|_default;|NavigationContainer;|KeyboardAwareNavigator;|Navigator;|StackView;|Transitioner;|withOrientation;|StackViewLayout;|ScreenContainer;|Container;|Card;|Screen;|AnimatedComponent;|SceneView;|NavigationContainer;|KeyboardAwareNavigator;|Navigator;|StackView;|Transitioner;|withOrientation;|StackViewLayout;|ScreenContainer;|Container;|Card;|Screen;|AnimatedComponent;|SceneView;|Wrapped;|Connect(ProductsScreen);|ProductsScreen;|FlatList;|VirtualizedList;|ScrollView;|CellRenderer;|ProductItem;[name=Foo];[price=$1.00];|TouchableOpacity;|
Capturing Properties from Nested Objects and Arrays
Prop capture configs also support capture of props from within more complex objects. For example, if the ProductItem
component utilized an item
prop instead of name
and price
, we could capture the props like this:
import React from 'react';
import { Text, TouchableOpacity, View } from 'react-native';
const ProductItem = ({item, onPress}) => {
return (
<TouchableOpacity onPress={onPress}>
<View>
<Text>{item.name}</Text>
<Text>{item.price}</Text>
</View>
</TouchableOpacity>
);
}
ProductItem.heapOptions = {
eventProps : { include: [ 'item.name', 'item.price' ] }
};
export { ProductItem };
Best Practices for Event Definition
For information on capturing and managing definitions in React Native, see the following:
- Using the Event Visualizer with React Native
- QAing React Native Definitions in Live View
- Managing React Native Event Definitions
Changelog
For notable updates to the Heap React library, see the React Changelog.
Updated 4 days ago