react-native-gleapsdk
v19.5.1
Published
Gleap SDK for React Native: AI customer support, live chat, in-app bug reporting and customer feedback.
Maintainers
Readme
Gleap React Native SDK

Add AI-native customer support, live chat, in-app bug reporting, a help center and surveys to your React Native apps with Gleap. Gleap is an Intercom alternative for software teams that connects customer conversations and feedback with product development.
SDK documentation · Website · Plans and pricing
Installation
npm install react-native-gleapsdk
cd ios && pod installiOS requirements
- iOS 15.0 or later
- React Native 0.75 or later (Expo SDK 52 or later)
The native Gleap iOS SDK is installed with Swift Package Manager: pod install adds the Gleap-iOS-SDK package (product Gleap) to the Pods project through React Native's spm_dependency, and Xcode resolves it on the next build. You don't add the package to your app yourself. Your Podfile must call react_native_post_install in its post_install hook, as the React Native and Expo templates do.
pod install logs a warning that a Swift package with static linking "might cause linker errors". You can ignore it: the SDK builds with the default static linkage as well as with USE_FRAMEWORKS=dynamic.
On React Native older than 0.75, pod install falls back to the Gleap pod from CocoaPods trunk and prints a warning. CocoaPods trunk is read-only from December 2, 2026, so only versions released before then are available this way.
Usage
// Import the SDK
import Gleap from "react-native-gleapsdk";
// Initialize it with your Project ID
Gleap.initialize('YOUR_PROJECT_ID');Find the Project ID in the Gleap dashboard under Settings → Project → General. It was called "SDK key" or "API key" before; the value is the same and existing keys keep working.
Data regions
Gleap projects are hosted in the EU by default. If your project lives in the US region, set the region before calling initialize:
Gleap.setRegion("us"); // "eu" (default) | "us"
Gleap.initialize('YOUR_PROJECT_ID');setRegion sets the API, websocket and realtime hosts at once. For dedicated servers you can still override a single host afterwards with setApiUrl, setWSApiUrl or setRealtimeHost.
Env data
With every ticket the SDK sends env data (device model, OS version, screen size, locale, battery state, …), shown under the Env data tab in Gleap. Leave out individual keys or stop collecting env data entirely:
Gleap.setEnvDataPropsToIgnore(['deviceName', 'batteryLevel']);
Gleap.setDisableEnvData(true);Both can be called at any time and apply to the next ticket. Each setEnvDataPropsToIgnore call replaces the previous list, an empty array resets it. setDisableEnvData(false) turns the collection back on.
Dark mode
Switch the widget between dark and light mode. auto follows the device appearance; if your app has its own theme toggle, pass light or dark explicitly and call it again whenever the theme changes:
Gleap.setColorScheme('auto');
Gleap.setColorScheme(isDarkTheme ? 'dark' : 'light', { darkBackgroundColor: '#121212' });setColorScheme only takes effect when "Adapt to dark / light mode" is enabled in the Gleap dashboard; it then overrides the dashboard's color scheme. Before the first call the dashboard setting applies. In dark mode the widget uses the dark mode colors, logo, header image and composer glow set in the Gleap dashboard; without dark colors it keeps its normal colors. lightBackgroundColor / darkBackgroundColor override the background in light / dark mode. Can be called before or after initialize.
Inline banners
Inline banners (the banner style set in the Gleap dashboard) sit at the top of the screen and cover the status bar. To push your app down below them instead of covering it, like inline banners on the web, wrap the app in GleapBannerArea:
import Gleap, { GleapBannerArea } from 'react-native-gleapsdk';
export default function App() {
return (
<GleapBannerArea>
<NavigationContainer>{/* ... */}</NavigationContainer>
</GleapBannerArea>
);
}While an inline banner is shown, the content moves down by the banner's height (animated) and back up when it closes; floating banners still float above the app. Without GleapBannerArea nothing changes: banners overlay the app as before.
The banner already covers the status bar, so screens that add the top safe-area inset themselves (React Navigation headers, SafeAreaView) would leave a gap below it. With react-native-safe-area-context, hand them the inset that is left:
import { SafeAreaInsetsContext, useSafeAreaInsets } from 'react-native-safe-area-context';
import { GleapBannerArea, useGleapBannerHeight } from 'react-native-gleapsdk';
function BannerSafeArea({ children }) {
const insets = useSafeAreaInsets();
const bannerHeight = useGleapBannerHeight();
return (
<SafeAreaInsetsContext.Provider value={{ ...insets, top: Math.max(0, insets.top - bannerHeight) }}>
{children}
</SafeAreaInsetsContext.Provider>
);
}
// <SafeAreaProvider><GleapBannerArea><BannerSafeArea><NavigationContainer>…useGleapBannerHeight() returns the height (points on iOS, dp on Android, measured from the top edge; 0 while no inline banner is shown) for custom layouts; Gleap.getBannerHeight() and the bannerHeightChanged listener (Gleap.registerListener('bannerHeightChanged', (height) => …)) give the same value.
Network logs
Network logs are recorded when they are turned on in the Gleap dashboard, or after you call Gleap.startNetworkLogging(). Gleap.stopNetworkLogging() turns them off again, also when the dashboard turns them on.
- iOS: the native SDK records every request of the app, including requests made by native modules.
- Android: the SDK records
fetchandXMLHttpRequestrequests (and libraries built on them, such as axios) in JavaScript and hands them to the native SDK.
Leave requests out or remove data before it leaves the device:
Gleap.setNetworkLogsBlacklist(['analytics.example.com']);
Gleap.setNetworkLogPropsToIgnore(['password', 'token', 'user.email']);setNetworkLogsBlacklist drops every request whose URL contains one of the strings. setNetworkLogPropsToIgnore removes headers, JSON keys (at any depth; a dotted name such as user.email also works as a path from the root), form fields and query parameters with these names, case-insensitively. Authorization, Proxy-Authorization, Cookie and Set-Cookie headers are always masked, and requests to Gleap itself are never logged. Each call replaces the previous list. Bodies over 150 KB are cut; binary and streaming bodies (images, server-sent events, …) are left out.
Sign in users (identity tokens)
Your backend signs a short HS256 JWT with an identity key from Settings → Security → Customer identity → Identity keys (put the key id in the kid header; the secret never leaves your server). The userId claim is required. Optional claims: email, name, company ({ id, name }), plan, and provider ids such as stripeCustomerId. Set exp to at most one hour. Everything in the token lands on the contact as signed data the app cannot change. Pass the token to the SDK with setUserJwt after login and on every app start of a logged-in user; no separate identify call is needed, and the token is kept in memory only. The optional setUserJwtProvider fetches a fresh token when it expires and, with the native 19.5.0 SDKs, restores the signed session after an app restart. Call clearIdentity on logout. setAuthTokens hands Kai your own API tokens for this user. See Customer identity and React Native user identity.
// After login and on every app start of a logged-in user
await Gleap.setUserJwt(token);
// Called when the token has expired or is about to; return a fresh one
Gleap.setUserJwtProvider(async () => {
const response = await fetch('https://api.example.com/gleap-token', {
headers: { Authorization: `Bearer ${accessToken}` },
});
const { token } = await response.json();
return token;
});
// Optional: shorten the signed session (milliseconds)
Gleap.setSessionDuration(24 * 60 * 60 * 1000);
// Optional: tokens API tools may use to call your backend as this user (null removes one)
await Gleap.setAuthTokens({ backend: accessToken });
// On logout
Gleap.clearIdentity();setSessionDuration(ms) shortens the signed session; the project's maximum applies.
setUserJwt resolves once the native SDK has the token, not when the server accepted it. Refusals (token_expired, token_invalid, signature_required) are logged by the native SDK: look in the Xcode console and in logcat under the tag Gleap, not in Metro. A token re-minted with the same claims (only iat/exp differ) is not sent again.
The identity handling runs in the native iOS and Android SDKs, so their behaviour applies here as is: setUserJwt and setUserJwtProvider may be called before or after initialize (a token is sent once the SDK starts), a returning user on a project that switched to Signed gets the identify of this app start sent once to obtain a signed session, and a short session duration is renewed at half its lifetime.
getIdentity() returns the contact the native SDK knows (user id and contact fields); it never contains the identity token or the grant.
Gleap.identify(userId, userProperties) without a token creates an unsigned contact.
Older integrations that pass a user hash to identifyWithUserHash keep working while "Accept legacy user hash" stays on in the project's security settings; see Upgrade to identity tokens.
Protected conversation files
With "Protect new files" (Settings → Security → Conversation files, see Authenticated conversation files), conversation files can only be opened by agents and by the verified customer the conversation belongs to. The SDK supports it without extra setup, as long as the app identifies the customer with a signed identity on every app start (Gleap.setUserJwt; older integrations that pass a user hash keep working).
A signed identify gives the session a short-lived file access token, which the native SDK keeps in memory only and renews while the app is in use. clearIdentity revokes it. Guests and contacts identified without a signed identity see "Sign in to view" instead of the file.
Email replies link attachments to your customer application URL with a gleapFile query parameter. If that URL opens your app (universal link / App Link), pass it to Gleap; the conversation opens once the customer is identified with a signed identity:
import { Linking } from 'react-native';
Linking.getInitialURL().then((url) => {
if (url) {
Gleap.openProtectedFileFromUrl(url);
}
});
Linking.addEventListener('url', ({ url }) => {
Gleap.openProtectedFileFromUrl(url);
});openProtectedFileFromUrl resolves true if the URL carries a Gleap file reference and false otherwise. The link alone grants no access; keep the parameter through your app's login flow.
Need help?
Checkout our full documentation or contact us - we are always here to help 👋.
