react-native-quantum-metric-library
v3.0.10
Published
Quantum Metric module for React Native
Downloads
13,274
Keywords
Readme
Quantum Metric React Native Module
This module is only for React Native apps and requires an account with Quantum Metric.
Note: You must first have already installed our Native SDKs before installing this module
What is this?
This module includes some extra features that improve our React Native capture support. You must have installed our Native SDKs on both iOS/Android before this native module can do anything. This module depends on having the native SDK already in the app.
Please refer to the platform-specific integration instructions located here -
iOS: https://community.quantummetric.com/s/article/iOS-SDK-Integration-Instructions Android: https://community.quantummetric.com/s/article/Android-Integration-Instructions
What is this used for?
- Adds support for Pages within Quantum. Navigation information is stored on the javascript side of react native, so in order to know the user moved to a new part of your app, we can do this with the Page Syncing with React Navigation integration (section below).
- Gives you full control over masking/encryption. Using the
QuantumComponent
(described below), you can let Quantum know which pieces of text displayed in your app should be masked (replaced with *** in replay) or encrypted (so that only the bearer of the private key on your team can decrypt and view that text). - Capturing network requests on Android. Depending on what version of react native you are using, we will automatically detect if we need to use this Module to grab network information that is not possible to grab from the native SDK.
Install React Native Module
First use npm (or yarn) to install this library.
npm install react-native-quantum-metric-library
Next import the library into the app component:
import { QuantumMetricLibrary } from 'react-native-quantum-metric-library';
Initialization
To initialize the library and get a session started, you have a number of options. The library MUST be initialized either from the javascript side OR from the native side.
Initializing directly from the javascript/typescript side
Initialization from the JS side can be achieved with one of two related functions:
function initialize (subscription: string, uid: string)
function initializeWithOptions(subscription: string, uid: string, options: {})
In each of these, the subscription
and uid
strings should be those provided by your QM contact. With the second function, the following options are available:
testModeEnabled: true/false
sslPinningEnabled: true/false
crashReportingEnabled: true/false
testModeEnabled will dictate whether production configuration or test configuration should be used. Using test mode can be helpful if you want to use different config in a development environment. sslPinningEnabled enables SSL certificate pinning for requests to Quantum Metric's servers. Please contact us if you'd like to enable this. (If you do enable it, you'll need to deploy a new build of the library when we get new SSL certificates) crashReportingEnabled will dictate whether QM will set itself as your app's crash handler. If you want to enable this, check with your QM team to make sure crash reporting is configured properly.
Calling either of these functions will initialize the Quantum Metric SDKs, both iOS and Android. We recommend calling these functions near the beginning of the app lifecycle to begin capture as soon as possible, such as in the componentDidMount()
of the App component, like so:
componentDidMount() {
QuantumMetricLibrary.initialize(<subscription>, <uid>);
}
Initializing from the native side
If you wish to initialize session capture from the native side, a little bit of JS work is still required. Add the following into the componentDidMount()
of the App component:
componentDidMount() {
QuantumMetricLibrary.init();
}
In addition to this, follow the initialization instructions detailed in the platform-specific integration guides:
iOS: https://community.quantummetric.com/s/article/iOS-SDK-Integration-Instructions Android: https://community.quantummetric.com/s/article/Android-Integration-Instructions
Masking and Encrypting Text in Components
As of version 3.0.0, this module includes a component you can use to wrap your components in, in order to mark them as needing masking/encryption.
Let's say you have a component that looks like this:
<Text>Your name:</Text>
<Text>First Last</Text>
<Text>Your address:</Text>
<Text>123 Address Street</Text>
You can wrap the Text
components with a QuantumComponent
, and pass in privacy parameters, for example:
<Text>Your name:</Text>
<QuantumComponent privacy="encrypt">
<Text>First Last</Text>
</QuantumComponent>
<Text>Your address:</Text>
<QuantumComponent privacy="mask">
<Text>123 Address Street</Text>
</QuantumComponent>
When this part of your app is captured, Quantum will send off an encrypted version of the name, and a masked version of the address. The address will never be sent to Quantum's servers.
Masking using this method has better performance that Quantum's remote masking capabilities, and gives you full control over user privacy.
Don't forget to import the component at the top of the file you're using it in:
import {QuantumMetricLibrary, QuantumComponent} from 'react-native-quantum-metric-library';
Unmasking Text in Components
As of version 3.0.6 of this package, you can pass in a privacy filter of "unmask"
to indicate that a view should not be masked. Please note that this requires the following versions of our native SDKs:
Android: 1.0.18
iOS: 1.1.11
This functionality is useful if you want to mark a view (and its subviews) as NOT containing any PII. For example, if your subscription has been figured with "mask everything mode", you can use this to mark views as safe for displaying their contents.
Using the example from above, suppose you have these components
<Text>Your name:</Text>
<Text>First Last</Text>
<Text>Your address:</Text>
<Text>123 Address Street</Text>
and your subscription has been set to mask-everything mode, such that all views are automatically masked. You can then specify that certain components do NOT need to be masked, like so:
<QuantumComponent privacy="unmask">
<Text>Your name:</Text>
</QuantumComponent>
<Text>First Last</Text>
<QuantumComponent privacy="unmask">
<Text>Your address:</Text>
</QuantumComponent>
<Text>123 Address Street</Text>
Page Syncing with React Navigation
Since React Native apps do not use Activities or View Controllers under the hood, we need to rely on the Javascript side to tell us when a "page" happens on the native side. This module includes the QuantumMetricLibrary.sendNewPageNamed()
function you can use to tell Quantum when a new page appeared.
React Navigation is one of the most common libraries used for navigation, so we'll show you one possible example integration here.
The render()
function of your main App component might look something like this:
render() {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Details" component={DetailsScreen} />
<Stack.Screen name="DeeperDetails" component={DeeperDetailsScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
The main idea is that we'll use onStateChange
in the NavigationContainer
to see when the route changes (which means the user navigated somewhere), and tell Quantum that the route changed, and pass in the new page name. The react docs refer to this as Screen Tracking, our implementation is similar to their example. If you have a Function component for your main App component, you can follow their example here, but most likely you have a Class component.
1. Create References
First we'll need to create references to the navigation container and route name, so we can see if it changed. In your constructor create these refs:
constructor(props) {
super(props);
this.navigationRef = React.createRef();
this.routeNameRef = React.createRef();
}
2. Use onRead and onStateChange listeners
Next, we'll setup the ref to the NavigationContainer, and use the onReady and onStateChange listeners to see if the new route is different than the old, and if it is, send the new page name to Quantum.
Replace <NavigationContainer>
with this:
<NavigationContainer
ref={this.navigationRef} //setup the reference so we can access the NavigationContainer later
onReady={() => //when the NavigationContainer becomes ready, setup the initial route
(this.routeNameRef.current = this.navigationRef.current.getCurrentRoute().name)
}
onStateChange={async () => { //whenever the state changes, get the new route and compare to the previous
const previousRouteName = this.routeNameRef.current;
const currentRouteName = this.navigationRef.current.getCurrentRoute().name;
if (previousRouteName !== currentRouteName) { //if the names are different, we can assume the user navigated
//call sendNewPage here (remove log when you see it's working)
console.log('send new page: ', currentRouteName);
QuantumMetricLibrary.sendNewPageNamed(currentRouteName)
}
//save the current route name for later comparison
this.routeNameRef.current = currentRouteName;
}}
>
That's it, you can test to make sure the send new page:
console log appears, and also that in your Quantum Replay you see the new page events happening. Please contact us if you have any questions.
Full example
import 'react-native-gesture-handler';
import React, { Component } from 'react';
import {
StyleSheet,
View,
Text,
Button
} from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import QuantumMetricLibrary from 'react-native-quantum-metric-library';
const Stack = createStackNavigator();
export default class App extends Component<{}> {
constructor(props) {
super(props);
this.navigationRef = React.createRef();
this.routeNameRef = React.createRef();
}
componentDidMount() {
if (QuantumMetricLibrary && QuantumMetricLibrary.initialize) {
QuantumMetricLibrary.initialize('mysubscription', '123');
} else {
console.error('error no QM lib!');
}
}
render() {
return (
<NavigationContainer
ref={this.navigationRef}
onReady={() =>
(this.routeNameRef.current = this.navigationRef.current.getCurrentRoute().name)
}
onStateChange={async () => {
const previousRouteName = this.routeNameRef.current;
const currentRouteName = this.navigationRef.current.getCurrentRoute().name;
if (previousRouteName !== currentRouteName) {
//call sendNewPage here
console.log('send new page: ', currentRouteName);
QuantumMetricLibrary.sendNewPageNamed(currentRouteName)
}
// Save the current route name for later comparison
this.routeNameRef.current = currentRouteName;
}}
>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Details" component={DetailsScreen} />
<Stack.Screen name="DeeperDetails" component={DeeperDetailsScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
}
class HomeScreen extends React.Component {
render() {
return (
<View style={styles.container}>
<Button title="Send New Page" onPress={() => QuantumMetricLibrary.sendNewPageNamed("ReactPageHello")}></Button>
<Button title="Go to Details" onPress={() => this.props.navigation.push('Details')} />
</View>
);
}
}
function DetailsScreen({ navigation }) {
return(
<View style={styles.container}>
<Text>Details screen!</Text>
<Button title="Push Deeper Details" onPress={() => navigation.push('DeeperDetails')} />
</View>
);
};
function DeeperDetailsScreen({ navigation }) {
return(
<View style={styles.container}>
<Text>Deeper Details screen!</Text>
<Button title="Push Regular Details" onPress={() => navigation.push('Details')} />
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
});
Adding a cookie and user string listener
As of version 3.0.6 of this package, you can add a cookie and user string listener via your JS/TS code, rather than having to do it through the native SDKs.
Please note that this requires version 1.0.18
of the Android SDK. On iOS, this is supported by all versions above 0.3.35
.
After initializing the QM module, you can set the listener using
function setSessionCookieCallbackQM(callback)
Example Doing something like the following will simply log the session cookie and user string once they are received:
componentDidMount() {
if (QuantumMetricLibrary && QuantumMetricLibrary.initializeWithOptions) {
QuantumMetricLibrary.initializeWithOptions('mysubscription', 'myUID', {'testModeEnabled': false, 'sslPinningEnabled': false, 'crashReportingEnabled': false});
QuantumMetricLibrary.setSessionCookieCallbackQM((sessionCookie, userString) => {
console.log('Got sessionCookie: ' + sessionCookie);
console.log('Got userString: ' + userString);
});
} else {
console.error('error no QM lib!');
}
}
The session cookie and user string can be helpful for logging and tracking purposes.
If the session cookie changes due to a new session beginning, this callback will get called again to let you know.
Manual Eventing
Quantum Metric has the ability to send manual events from your React Native application directly. This is helpful if you want a specific type of data inside Quantum Metric's platform.
To send a manual event, the Quantum Metric Library has
function sendEvent (eventId: number, value?: string, flags?: number):
eventId is the id
of your event in the Quantum Metric platform.
Please note: It is required to have an event with a corresponding id
set up in the platform before sendEvent will work correctly.
value is the data you'd like to send to the Quantum Metric platform.
flags provide special instructions to the Quantum Metric platform to organize how the value is interpreted. This can be accessed by calling eventType.EventTypeHere
.
Full list of Event Types:
EventTypeConversion
EventTypeLogin
EventTypeEmail
EventTypeFirstName
EventTypeLastName
EventTypeCartValue
EventTypeABN
EventTypeEncrypted
Example Let's say you'd like to record an order number, and you already have a function like this:
function completeOrder(cartValue) {
let orderNumber = confirmPurchase(cartValue);
if (orderNumber) {
console.log("Purchase Confirmed!");
return orderNumber;
}
return -1;
}
This will log a message when the purchase has successfully gone through. But let's go ahead and change our log to send an event to Quantum Metric. First, we'll replace our console.log
with sendEvent
:
function completeOrder(cartValue) {
let orderNumber = confirmPurchase(cartValue);
if (orderNumber) {
QuantumMetricLibrary.sendEvent(10);
return orderNumber;
}
return -1;
}
As you can see, we've provided an event id. This will now fire in the Quantum Metric platform whenever an order is confirmed. Next, let's send the order number as well:
function completeOrder(cartValue) {
let orderNumber = confirmPurchase(cartValue);
if (orderNumber) {
QuantumMetricLibrary.sendEvent(10, orderNumber);
return orderNumber;
}
return -1;
}
Now, the event will also include an order number when the event fires! However, this can sometimes be sensitive data, so let's encrypt that value. To do this, we'll use the flag
parameter by adding the EventTypeEncrypted
value:
function completeOrder(cartValue) {
let orderNumber = confirmPurchase(cartValue);
if (orderNumber) {
QuantumMetricLibrary.sendEvent(10, orderNumber, QuantumMetricLibrary.eventType.EventTypeEncrypted);
return orderNumber;
}
return -1;
}
And there we have it! Now, in this example, every time the app successfully completes an order, the order number will populate in the Quantum Metric platform as an encrypted value.
Another common example is order conversion:
QuantumMetricLibrary.sendEvent(123, orderValue, QuantumMetricLibrary.EventTypeConversion);
Other Features
Several other functions can be performed with the QuantumMetricLibrary, mostly related to sessions. They are as follows:
pauseQM
This will pause the current session, without ending it. Capture will cease until the session is resumed. Please note that if a session is paused for more than 30 minutes, a brand new session will begin the next time it is resumed.
QuantumMetricLibrary.pauseQM()
resumeQM
If this is called after a session has been paused, it will resume the session. If the session has been paused for more than 30 minutes, a new session will begin. If this is called while a session is still running, it will do nothing.
QuantumMetricLibrary.resumeQM()
stopQM
Calling this will end the current session. The session will be terminated and capture will cease until a new session is started.
QuantumMetricLibrary.stopQM()
resetSessionQM
Calling this will end any existing session and begin a new one. If no session is currently active, it will simply begin a new one. This function takes one boolean argument, indicating whether or not the user should be reset.
QuantumMetricLibrary.resetSessionQM(shouldResetUser)
To resume capture after it's been paused, call: QuantumMetricLibrary.resumeQM()
Release Notes
3.0.10
17 April 2023
- Fix typescript API
3.0.9
15 February 2023
-Fix a bug related to capturing API data
3.0.8
27 June 2022
-Add support for React Native version 0.69
3.0.7
4 March 2022
-Add pause/resume API
3.0.5
3 February 2022
-Add initializeWithOptions with Android/iOS support
3.0.4
26 January 2022
-Add event type definitions, sendEvent API examples
3.0.3
29 November 2021
-Android remove support dependency
-Fix network interception race conditions
3.0.2
15 December 2021
-Add Typescript definitions
3.0.1
29 November 2021
-Documentation improvements
3.0.0
24 November 2021
-Initial launch of QuantumComponent