React Native
Later sections cover rewards, user attributes, the user identifier, Quick Questions, boosts, and placement details.
Testing? Your app starts in test mode, so you'll need a test device to see content while you build.
Installation
If your app's targetSdk is 35 or higher, use react-native-tapresearch 3.5.3 or higher — Android 15 introduced a change that otherwise cuts off the top title bar of the Survey Wall.
Replace <version> below with your SDK version from npm.
Run the following command:
yarn add react-native-tapresearch@<version>
- iOS
- Android
Install the iOS pods:
cd ios && pod install
- 3.7.x and 3.8.0: The TapResearch iOS framework ships with
react-native-tapresearchand is linked automatically, so no manual pod entry is needed. - 3.8.1 and later: CocoaPods adds the TapResearch iOS SDK as a Swift Package. Requires React Native 0.75 or later and iOS 15.0 or later. No manual pod or package entry is needed.
-
3.7.x: In build.gradle of your app, add
maven { url "https://artifactory.tools.tapresearch.io/artifactory/tapresearch-android-sdk/" }in theallprojects/repositoriessection:allprojects {repositories {...maven { url "https://artifactory.tools.tapresearch.io/artifactory/tapresearch-android-sdk/" }...}} -
3.8 and later: The TapResearch Android SDK is published to Maven Central, so no extra repository is needed as long as
mavenCentral()is in your repositories.
Integration
Import the TapResearchSDK components
import {
PlacementCustomParamsProps,
TapSdkAdapter,
TapSdkUI,
TapUserAttributes,
TapSdkReward,
TapSdkError,
TRQQDataPayload,
TapSdkGrantBoostResponse,
TapSdkPlacementDetails,
} from 'react-native-tapresearch';
Initialization
Initialize the TapResearchSDK as early as possible so TapResearch can start getting surveys ready for your users. Call initializeSdk() once, after <TapSdkUI> has mounted and registered its callbacks. Use the API token of the matching app — your iOS and Android apps have different API tokens.
The user identifier passed through initialization must be unique! Only initialize once you are able to provide a unique identifier. Re-using the same user identifier is not supported and will prevent your users from accessing our service.
Parameters
- apiToken - your app's API token, from its Settings tab in the Publisher Dashboard
- userIdentifier - unique identifier assigned to the current user of your app
- userAttributes - optional; map with string keys and string or number values, used for targeting content
- clearPreviousAttributes - optional boolean, default
false; remove all user attributes previously assigned to userIdentifier
// export type TapUserAttributes = Record<string, any>;
// TapSdkAdapter.initializeSdk(apiToken: string, userIdentifier: string, userAttributes?: TapUserAttributes | null, clearPreviousAttributes = false)
TapSdkAdapter.initializeSdk("YOUR_IOS_OR_ANDROID_API_TOKEN", "USER_IDENTIFIER");
// Or, with user attributes known at initialization:
TapSdkAdapter.initializeSdk("YOUR_IOS_OR_ANDROID_API_TOKEN", "USER_IDENTIFIER", userAttributes, false);
SDK callbacks setup
The SDK will call delegate functions to notify the app of certain events, for example to pass rewards or to notify the SDK has taken over the UI.
Define the callback functions with the following signatures. The first four are required props of <TapSdkUI>; the rest are optional:
onTapResearchSdkReady: () => void;
onDidReceiveError: (error: TapSdkError) => void;
onContentShown: (placementTag: string) => void;
onContentDismissed: (placementTag: string) => void;
onDidReceiveRewards?: (rewards: Array<TapSdkReward>) => void;
onDidReceiveQQResponse?: (qqResponse: TRQQDataPayload) => void;
onSurveysRefreshedForPlacement?: (placementTag: string) => void;
onGrantBoostResponse?: (boostResponse: TapSdkGrantBoostResponse) => void;
Errors are passed as a TapSdkError:
export type TapSdkError = {
error_code: number;
message: string;
};
For example, a reward callback may look like this:
function doRewards(rewards: Array<TapSdkReward>) {
console.log('Received some rewards', rewards);
}
Make sure to render the TapSDK component with the previously defined callbacks as its properties:
<TapSdkUI
onTapResearchSdkReady={onTapResearchSdkReady}
onDidReceiveError={onError}
onContentShown={contentShown}
onContentDismissed={contentDismissed}
onDidReceiveRewards={doRewards}
onDidReceiveQQResponse={onQQResponse}
/>
Keep <TapSdkUI> mounted with the callbacks you need, for example in your root component.
Checking if the SDK is ready
As mentioned above, you can determine when the SDK is ready via the onTapResearchSdkReady callback.
Alternatively, you can also call the isReady method:
TapSdkAdapter.isReady()
It may look something like this (example in Typescript):
const isReady = useCallback(() => {
TapSdkAdapter.isReady()
.then((result: any) => {
console.log(`TapSdkAdapter.isReady() - Result: ${result}`);
Toast.hide();
Toast.show({
type: result ? 'success' : 'error',
text1: 'TapSdkAdapter.isReady?',
text2: result.toString(),
});
})
.catch((error: any) => {
console.error(error);
});
}, []);
<Button
onPress={isReady}
>
Displaying a placement
Placements are locations and moments inside the app when content can be shown. To show content for a placement, you'll need to specify a placement tag.
Note that the show content calls are wrapped in a canShowContent check. This is to ensure that the placement is ready to be shown. If the placement is not ready, the SDK will return false.
This helps guard against showing the user something that is not ready to be shown yet.
Placement tags can be found in your TapResearch dashboard on the App Settings page.
TapSdkAdapter.showContentForPlacement("YOUR_PLACEMENT_TAG");
Checking that a placement is available
You can check whether a placement is available by using canShowContentForPlacement(). It is recommended that you wrap showContentForPlacement calls with canShowContentForPlacement() to handle situations when a placement may not be available.
const placementTag = "YOUR_PLACEMENT_TAG";
TapSdkAdapter.canShowContentForPlacement(placementTag)
.then((canShowPlacement: boolean) => {
console.log(`canShowPlacement is ${canShowPlacement}`);
if (canShowPlacement) {
TapSdkAdapter.showContentForPlacement(placementTag);
}
})
.catch((error: any) => {
console.error(error);
});
Passing custom parameters
Custom parameters allow you to receive additional information about the user when they complete a survey. This can be used to filter out users who have already completed a survey, or to target specific users.
These params will be returned via server-to-server postbacks.
Parameters can only be ASCII characters, Unicode is not supported. You can send a maximum of 5 custom parameters.
let customParams: PlacementCustomParamsProps = {
number: 1,
string: 'string',
boolean: true
};
TapSdkAdapter.showContentForPlacement("YOUR_PLACEMENT_TAG", customParams);
Receiving rewards
In the reward callback onDidReceiveRewards: (rewards: Array<TapSdkReward>) => void; you will receive an array of TapSdkReward objects which contain information about each reward such as amount and currency name:
export type TapSdkReward = {
transactionIdentifier: string;
placementTag: string;
placementIdentifier: string;
currencyName: string;
payoutEvent: string;
rewardAmount: number;
};
See TRReward for a description of each field and its payout event values.
Send user attributes
User attributes let you target content to specific users. Send attributes at initialization or update them after the SDK is ready.
User attributes are passed as a dictionary of key-value pairs.
If user attributes are known at SDK initialization, it is preferable to pass them as the userAttributes argument of initializeSdk compared to using sendUserAttributes. This will result in quicker load times for targeted content.
Attribute names must be strings and must not begin with tapresearch_, which is reserved for TapResearch. Use string or numeric values for targeting. For booleans, send "true"/"false" or 0/1 instead of native booleans.
Set clearPreviousAttributes to false to merge new values with existing attributes, or true to replace the attributes you previously sent.
// const clearPreviousAttributes = false; // combine new attributes with user attributes previously assigned to current user
const clearPreviousAttributes = true; // remove any user attributes previously assigned to current user
const now = new Date();
const userAttributes: TapUserAttributes = {
boolean: 'true',
integer: 1,
double: 1.1,
string: 'string',
isVIP: "true",
now: now.toISOString(),
};
TapSdkAdapter.sendUserAttributes(userAttributes, clearPreviousAttributes);
Update user identifier
You can set the user identifier at any time. This is done by calling setUniqueUserIdentifier with a string.
TapSdkAdapter.setUniqueUserIdentifier("USER_IDENTIFIER");
Quick Question response
New to Quick Questions? See Quick Questions for what they are and the response payload.
A new callback is called whenever a Quick Question is completed:
onDidReceiveQQResponse: (qqResponse: TRQQDataPayload) => void;
Pass it to <TapSdkUI> as the onDidReceiveQQResponse prop:
const onQQResponse = useCallback((qqResponse: TRQQDataPayload) => {
console.log('Quick Question answered', qqResponse.survey_identifier);
}, []);
<TapSdkUI
// ...required callbacks
onDidReceiveQQResponse={onQQResponse}
/>
This callback will return a TRQQDataPayload object (see below). This callback will get called regardless of whether or not a Quick Question server-to-server postback URL is set on your dashboard (unlike the onDidReceiveRewards). This in app callback allows process and handle the response client side in a way that may otherwise be delayed with server-to-server postbacks. Ex: If a user likes your application, direct them to a link to the app store where they can leave a review.
Quick Question types
export type TRQQDataPayload = {
survey_identifier : string;
app_name : string;
api_token : string;
sdk_version : string;
platform : string;
placement_tag : string;
user_identifier : string;
user_locale : string;
seen_at : string;
questions : [TRQQDataPayloadQuestion];
target_audience? : [TRQQDataPayloadTargetFilter];
complete? : TRQQComplete;
};
export type TRQQComplete = {
complete_identifier : string;
completed_at : string;
};
export type TRQQUserAnswer = {
value : string;
identifiers : [string];
};
export type TRQQDataPayloadQuestion = {
question_identifier : string;
question_text : string;
question_type : string;
rating_scale_size? : number;
user_answer? : TRQQUserAnswer;
};
export type TRQQDataPayloadTargetFilter = {
filter_attribute_name : string;
filter_operator : string;
filter_value : string;
user_value : string;
};
Granting boosts
Call grantBoost with a configured User Boosts tag:
TapSdkAdapter.grantBoost("YOUR_BOOST_TAG");
Receive the result in onGrantBoostResponse:
<TapSdkUI
// ...required callbacks
onGrantBoostResponse={(response) => {
if (response.success) {
console.log(`Boost granted: ${response.boost_tag}`);
} else {
console.log(`Boost failed: ${response.error?.message}`);
}
}}
/>
Getting placement details
Get placement details by calling:
async getPlacementDetails(placementTag: string): Promise<TapSdkPlacementDetails | null>
It will return TapSdkPlacementDetails:
export type TapSdkPlacementDetails = {
name: string;
content_type: string;
currency_name: string;
is_sale: boolean;
sale_type: string | null; //'sale' | 'boost'
sale_end_date: string | null;
sale_multiplier: number;
sale_display_name: string | null;
sale_tag: string | null;
bonus_bar_progress: TapSdkBonusBarProgress | null;
};
type TapSdkBonusBarProgress = {
is_active: boolean;
current_completes: number;
bonus_window_end_at: string | null;
bonus_tiers: [TapSdkBonusTier] | null;
error: TapSdkError | null;
};
type TapSdkBonusTier = {
tier_number: number;
completes_needed: number;
reward_amount: number;
status: string | null;
};
Get placement details example
<Button onPress={getPlacementDetails}>
Get Placement Details
</Button>
const getPlacementDetails = useCallback(() => {
TapSdkAdapter.getPlacementDetails('earn-center')
.then((result: TapSdkPlacementDetails | null) => {
if (result != null) {
alert( "Placement Details: "
+ result.name
+ " currency_name: " + result.currency_name
+ " is_sale: " + result.is_sale
+ " sale_type: " + result.sale_type
+ " sale_multiplier: " + result.sale_multiplier
+ " sale_display_name: " + result.sale_display_name
+ " sale_tag: " + result.sale_tag
+ " content_type: " + result.content_type
+ " sale_end_date: " + result.sale_end_date
);
}
})
.catch((error: any) => {
console.error(error);
});
}, []);
Need help?
Email developers@tapresearch.com.
Stay updated: see react-native-tapresearch on npm for new releases.