Create workspace
Create your organization, select a plan, and complete project setup in the AppRainier admin portal.
Developer integration guide
Use this guide to install the v1.0 SDKs, initialize AppRainier, identify users, track events, show surveys and announcements, render live cards, evaluate feature flags, and launch Message Center across Android, iOS, Flutter, React Native, and Web.
await AppRainier.initializeWithConfig(config);
await AppRainier.identify('user_123', { email: 'user@example.com' });
await AppRainier.trackEvent('checkout_started', { total: 89.99 });
await AppRainier.showSurvey('thumbs_up_down_feedback_survey');
How to use AppRainier
Create your organization, select a plan, and complete project setup in the AppRainier admin portal.
Create a client SDK API key and download its config JSON file. Each API key gets its own config file.
Download the SDK for your platform and add the config file to the app bundle, assets, or public web path.
Initialize AppRainier when the app starts. Then identify users and set app/device properties.
Create surveys, live cards, announcements, flags, experiments, and Message Center settings in the admin portal.
Review analytics, responses, AI insights, engagement stats, and usage from the admin portal.
v1.0 downloads
Reference test apps
Each test app shows a complete AppRainier setup for its platform: SDK installation, config-file initialization, user registration, event tracking, surveys, live cards, announcements, feature flags, Message Center, and callback handling.
Common SDK flow
Trigger IDs and events
Use readable snake_case IDs such as checkout_exit_survey, maintenance_alert_announcement, or promotions_showcase_carousel.
Track lifecycle events such as dashboard_opened, checkout_started, purchase_completed, and support_chat_opened.
Send traits that are useful for targeting, for example plan, country, signup date, purchase count, or role.
Always pass safe defaults to feature flags so your app behavior stays predictable during first launch or offline use.
Android integration
Download Android SDKapp/libs/apprainier-android-sdk-release.aar.apprainier-config.json to app/src/main/assets/.setCurrentActivity so the SDK can present native UI.class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
AppRainier.initialize(
context = this,
configAssetPath = "apprainier-config.json",
) { state ->
if (state == SDKState.READY) {
AppRainier.setCurrentActivity(this)
AppRainier.setAppProperty("app_version", "1.0.0")
AppRainier.setDeviceProperty("platform", "android")
}
}
}
override fun onResume() {
super.onResume()
if (AppRainier.isInitialized() && AppRainier.isReady()) {
AppRainier.setCurrentActivity(this)
}
}
}
AppRainier.identify("user_123", mapOf("email" to "user@example.com"))
AppRainier.trackEvent("checkout_started", mapOf("cart_value" to 49.99))
AppRainier.showSurvey("thumbs_up_down_feedback_survey", this, surveyCallback)
AppRainier.showAnnouncement("maintenance_alert_announcement", this, announcementCallback)
AppRainier.createLiveCardView("live_card_discount_product", this) { view ->
if (view != null) container.addView(view)
}
val promoEnabled: Boolean = AppRainier.getFeatureFlag("promo_status", false)
AppRainier.trackExperimentExposure("button_color_experiment")
AppRainier.trackExperimentConversion("button_color_experiment", "button_tapped", 1)
val unread = AppRainier.getUnreadMessageCount()
if (AppRainier.canShowMessageCenter()) {
AppRainier.openMessageCenter(this, initialTab = "messages")
}
private val surveyCallback = object : SurveyCallback {
override fun onSurveySubmitted(
surveyId: String,
responses: Map<String, Any>,
targetScreen: String?,
deepLink: String?
) {
Log.d("AppRainier", "Survey submitted: $surveyId")
}
override fun onSurveyCancelled(
surveyId: String,
targetScreen: String?,
deepLink: String?
) {
Log.d("AppRainier", "Survey cancelled: $surveyId")
}
override fun onSurveyDismissed(surveyId: String) {
Log.d("AppRainier", "Survey dismissed: $surveyId")
}
}
private val announcementCallback = object : AnnouncementCallback {
override fun onAnnouncementSubmitted(
announcementId: String,
responses: Map<String, Any>,
targetScreen: String?,
deepLink: String?
) {
Log.d("AppRainier", "Announcement action: $announcementId")
}
override fun onAnnouncementCancelled(
announcementId: String,
targetScreen: String?,
deepLink: String?
) {
Log.d("AppRainier", "Announcement cancelled: $announcementId")
}
override fun onAnnouncementDismissed(announcementId: String) {
Log.d("AppRainier", "Announcement dismissed: $announcementId")
}
}
iOS integration
Download iOS SDKAppRainierSdk.xcframework to your Xcode project.apprainier-config.json to the app target bundle and enable target membership.AppRainierOverlayHost so SDK UI can be presented.import AppRainierSdk
import SwiftUI
@main
struct YourApp: App {
@StateObject private var appRainier = AppRainier.shared
var body: some Scene {
WindowGroup {
AppRainierOverlayHost(sdk: appRainier) {
ContentView()
}
.task {
appRainier.initialize(configFileName: "apprainier-config") { state in
if state.isReady {
appRainier.setAppProperty("app_version", value: "1.0.0")
appRainier.setDeviceProperty("platform", value: "ios")
}
}
}
}
}
}
AppRainier.shared.identify(
userId: "user_123",
traits: ["email": "user@example.com"]
)
AppRainier.shared.trackEvent(
"checkout_started",
properties: ["cart_value": 49.99]
)
let survey = await AppRainier.shared.showSurvey("thumbs_up_down_feedback_survey")
let announcement = await AppRainier.shared.showAnnouncement("maintenance_alert_announcement")
let hasCard = await AppRainier.shared.hasLiveCard(triggerId: "live_card_discount_product")
let promoEnabled: Bool = await AppRainier.shared.getFeatureFlag("promo_status", defaultValue: false)
await AppRainier.shared.trackExperimentExposure("button_color_experiment")
await AppRainier.shared.trackExperimentConversion("button_color_experiment", goalId: "button_tapped", value: 1)
let unread = AppRainier.shared.getUnreadMessageCount()
await AppRainier.shared.refreshMessageCenter()
AppRainier.shared.openMessageCenter(initialTab: "messages")
struct MySurveyCallback: SurveyCallback {
func onSurveySubmitted(_ result: SurveyPresentationResult) {
print("Survey submitted", result.surveyId)
}
func onSurveyCancelled(surveyId: String, targetScreen: String?, deepLink: String?) {
print("Survey cancelled", surveyId)
}
func onSurveyDismissed(surveyId: String) {
print("Survey dismissed", surveyId)
}
}
let surveyShown = await AppRainier.shared.showSurvey(
"thumbs_up_down_feedback_survey",
callback: MySurveyCallback()
)
struct MyAnnouncementCallback: AnnouncementCallback {
func onAnnouncementSubmitted(_ result: AnnouncementPresentationResult) {
print("Announcement action", result.announcementId)
}
func onAnnouncementCancelled(announcementId: String, targetScreen: String?, deepLink: String?) {
print("Announcement cancelled", announcementId)
}
func onAnnouncementDismissed(announcementId: String) {
print("Announcement dismissed", announcementId)
}
}
let announcementShown = await AppRainier.shared.showAnnouncement(
"maintenance_alert_announcement",
callback: MyAnnouncementCallback()
)
Flutter integration
Download Flutter SDKflutter:
assets:
- assets/apprainier-config.json
import 'package:flutter_apprainier_plugin/flutter_apprainier_plugin.dart';
await AppRainier.initializeFromConfigAsset('assets/apprainier-config.json');
await AppRainier.setUserProfile(
const AppRainierUserProfile(
userId: 'user_123',
userType: 'registered',
userProperties: {'email': 'user@example.com'},
),
);
await AppRainier.trackEvent('checkout_started', properties: {'cartValue': 42});
final shown = await AppRainier.showSurvey('thumbs_up_down_feedback_survey');
final opened = await AppRainier.showAnnouncement('maintenance_alert_announcement');
SizedBox(
height: 220,
child: AppRainierLiveCardView(
triggerId: 'promotions_showcase_carousel',
onCardClick: (payload) {
debugPrint('Live card clicked: $payload');
},
),
);
final unread = await AppRainier.getUnreadMessageCount();
await AppRainier.openMessageCenter();
final surveySubscription = AppRainier.addSurveyCallback(
AppRainierSurveyCallback(
onSurveySubmitted: (payload) => debugPrint('Survey submitted: $payload'),
onSurveyDismissed: (payload) => debugPrint('Survey dismissed: $payload'),
),
);
final announcementSubscription = AppRainier.addAnnouncementCallback(
AppRainierAnnouncementCallback(
onAnnouncementSubmitted: (payload) => debugPrint('Announcement action: $payload'),
),
);
// Later, when the widget is disposed:
surveySubscription.remove();
announcementSubscription.remove();
FlutterFragmentActivity. iOS Flutter hosts should run pod install after adding the plugin.React Native integration
Download React Native SDKimport AppRainier, { AppRainierLiveCardView } from 'react-native-apprainier-plugin';
import config from './apprainier-config.json';
await AppRainier.initializeWithConfig(config);
await AppRainier.setUserProfile({
userId: 'user_123',
userType: 'registered',
userProperties: { email: 'user@example.com' },
});
await AppRainier.trackEvent('checkout_started', { cartValue: 42 });
await AppRainier.showSurvey('thumbs_up_down_feedback_survey');
await AppRainier.showAnnouncement('maintenance_alert_announcement');
<AppRainierLiveCardView
triggerId="live_card_discount_product"
style={{ width: '100%', height: 180 }}
onCardClick={({ nativeEvent }) => {
console.log('Live card clicked', nativeEvent);
}}
/>
await AppRainier.refreshFeatureFlags(true);
const enabled = await AppRainier.getFeatureFlag('promo_status', false);
await AppRainier.openMessageCenter({ initialTab: 'messages' });
const unread = await AppRainier.getUnreadMessageCount();
const subscription = AppRainier.addSurveyCallback({
onSurveySubmitted: payload => console.log(payload),
onSurveyDismissed: payload => console.log(payload),
});
subscription.remove();
Web integration
Download Web SDKimport { AppRainier } from '@apprainier/web-sdk';
await AppRainier.initializeFromConfigUrl('/apprainier-config.json');
await AppRainier.identify('user_123', { email: 'user@example.com' });
await AppRainier.trackEvent('checkout_completed', { total: 89.99 });
await AppRainier.showSurvey('survey_star_rating_prompt');
await AppRainier.showAnnouncement('maintenance_alert_announcement');
const card = await AppRainier.createLiveCard('live_card_discount_product');
document.querySelector('#live-card-slot').replaceChildren(card);
const promoEnabled = await AppRainier.getFeatureFlag('promo_status', false);
await AppRainier.openMessageCenter({ initialTab: 'messages' });
AppRainier.addSurveyCallback({
onSurveySubmitted: payload => console.log('survey submitted', payload),
onSurveyDismissed: payload => console.log('survey dismissed', payload),
});
AppRainier.addAnnouncementCallback({
onAnnouncementSubmitted: payload => console.log('announcement action', payload),
});
Callbacks and app behavior
API reference
Loads the SDK config and prepares runtime settings, local cache, event queue, and UI surfaces.
Associates activity with a known user and sends user, app, device, and custom properties.
Queues product events. Use stable event names such as checkout_started or dashboard_opened.
Attempts to upload queued telemetry. Call before logout or when the app is about to close.
Shows an eligible survey for the trigger ID. Returns false/nil when no eligible survey exists.
Shows an eligible announcement or banner and reports CTA actions through callbacks.
Refresh cards, check eligibility, render SDK card UI, and receive click payloads.
Returns a boolean/string/variant value with the supplied fallback when unavailable.
Records that a user saw an experiment or variant.
Records conversion goals and optional values for experiment results.
Refresh settings, open Message Center, and read unread message count.
Forward push tokens and AppRainier-owned notification payloads from the host app.
Errors and troubleshooting
Initialize once before calling feature APIs. Make sure the config file is present and included in the app build.
The item may be archived, unpublished, outside its schedule, over impression limits, blocked by cooldown, or not matching targeting.
Check the flag key, published status, audience rules, default value type, and whether the SDK has refreshed runtime config.
Confirm the trigger ID, targeting rules, published status, image access, dimensions, and platform-specific native view setup.
Enable Message Center in settings, identify the user, refresh Message Center settings, and verify chat support is enabled if using messages.
Events are batched for efficiency. Call flush() before logout or when you need immediate upload.
Production release checklist