The example app is a reference integration of the Klaviyo React Native SDK. It demonstrates a basic Klaviyo integration with all major SDK features including:
- Initialization
- Analytics
- Push Notifications
- Geofencing
- Deep Linking
- In-App Forms
The example source is annotated with RN|iOS|Android Installation Step comments that mark
the code an integrator needs to replicate in their own app. Grep for any of those prefixes
across example/ to walk the integration surface:
RN Installation Step—example/src/App.tsxandexample/index.js(SDK init, API key sourcing, optional@react-native-firebase/messagingbackground handler)iOS Installation Step—example/ios/KlaviyoReactNativeSdkExample/AppDelegate.swift,NotificationService.swift, and the PodfileAndroid Installation Step—example/android/build.gradle,app/build.gradle,AndroidManifest.xml, andMainActivity.kt
The app loads your Klaviyo public API key from a gitignored .env file via
react-native-dotenv.
- Copy the template:
cp .env.template .env - Edit
.envand setKLAVIYO_API_KEY=to your actual public API key (.envis gitignored) - Restart Metro with
yarn start --reset-cacheso the metro picks up the new value
If you hit "Klaviyo API key not configured" after setting up
.env: Metro inlines.envvalues at bundle time viareact-native-dotenv. If Metro was already running when you created or edited.env, it will serve a cached bundle withKLAVIYO_API_KEYstill undefined. Stop Metro and restart it withyarn start --reset-cache(fromexample/).
The one-liner, run from the repo root:
# From the repo root
yarn example setup
# This alias runs:
# yarn install --immutable (repo root)
# bundle install (example/)
# bundle exec pod install (example/ios/)Preferred — from the repo root (yarn workspaces entry point):
# From the repo root
yarn example start
yarn example android
yarn example iosPush notifications are handled via @react-native-firebase/messaging in the
JavaScript layer — the Klaviyo SDK is initialized from JS, and Firebase manages
push tokens cross-platform.
Android builds and runs out of the box without Firebase configured. The
com.google.gms.google-services plugin is conditionally applied only when
google-services.json is present. Without the file, push features are dormant
but everything else (profile, events, in-app forms, geofencing) works normally.
- To enable push: drop a real
google-services.jsonfrom your Firebase project intoexample/android/app/. The file is gitignored. Ensure theapplicationIdinexample/android/app/build.gradle(com.klaviyoreactnativesdkexample) is registered as an Android app in your Firebase project.
iOS requires a GoogleService-Info.plist at example/ios/ to build at all — the Xcode
project's Resources build phase references it unconditionally. Two options:
-
To enable push: drop a real
GoogleService-Info.plistfrom your Firebase project atexample/ios/GoogleService-Info.plist(gitignored). Ensure your iOS bundle identifier is registered in the same Firebase project. -
To build without push: write a stub plist at the same path. The values below are format-valid (39-char
API_KEYstarting withA, fullGOOGLE_APP_IDformat), soFirebaseApp.configure()succeeds at launch. Firebase will log a benign "couldn't register with backend" warning at runtime since the project isn't real — that's expected, not a bug. The rest of the app works normally.Stub
GoogleService-Info.plist<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>BUNDLE_ID</key><string>com.klaviyoreactnativesdkexample</string> <key>GOOGLE_APP_ID</key><string>1:000000000000:ios:0000000000000000000000</string> <key>API_KEY</key><string>AIzaSyA00000000000000000000000000000000</string> <key>GCM_SENDER_ID</key><string>000000000000</string> <key>PROJECT_ID</key><string>stub-project</string> <key>STORAGE_BUCKET</key><string>stub-project.appspot.com</string> <key>PLIST_VERSION</key><string>1</string> <key>IS_GCM_ENABLED</key><true/> <key>IS_ADS_ENABLED</key><false/> <key>IS_ANALYTICS_ENABLED</key><false/> <key>IS_APPINVITE_ENABLED</key><false/> <key>IS_SIGNIN_ENABLED</key><false/> </dict> </plist>
For apps that prefer to handle push tokens natively (e.g., brownfield apps), the
Klaviyo iOS and Android SDKs both have their own native push APIs. See the
AppDelegate.swift comments on iOS and MainApplication.kt comments on Android for
pointers, plus the platform SDKs' READMEs:
- iOS: https://github.com/klaviyo/klaviyo-swift-sdk#push-notifications
- Android: https://github.com/klaviyo/klaviyo-android-sdk#push-notifications
Note: both platforms require native-layer push-open handling regardless of how tokens are managed:
- Android:
Klaviyo.handlePush(intent)inMainActivity.kt(onCreate+onNewIntent) — covers cold-start taps and resume-from-background taps. - iOS:
Push.handleReceivingPush(response:...)inside theuserNotificationCenter(_:didReceive:withCompletionHandler:)delegate inAppDelegate.swift, plus thegetLaunchOptionsWithURLhelper to forward any cold-start deep-link URL (React Native issue #32350).