LogDrop React Native SDK
The LogDrop React Native SDK provides a JavaScript/TypeScript API on top of the native iOS and Android SDKs.
You initialize LogDrop once in your React Native app and it forwards logs, crashes and network data to the LogDrop backend.
1. SDK Installation
1.1. Add the npm package
yarn add @log-drop/react-nativenpm install @log-drop/react-native --save1.2. iOS setup
ios folder:cd ios
pod install
cd ..Configure the LogDrop project
Create ios/LogDrop-Services.plist. Replace com.example.app with the
target's bundle identifier and YOUR_LOGDROP_APP_ID with the App ID from
the LogDrop panel.
<?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>base_url</key>
<string>https://server.logdrop.io</string>
<key>projects</key>
<dict>
<key>com.example.app</key>
<dict>
<key>app_id</key>
<string>YOUR_LOGDROP_APP_ID</string>
</dict>
</dict>
</dict>
</plist>Add another entry under projects for each bundle identifier that uses a
different LogDrop project, such as development and production targets.
Generate the React Native source map
In Build Phases → Bundle React Native code and images, add this line before the standard React Native bundle command:
export EXTRA_PACKAGER_ARGS="--sourcemap-output $CONFIGURATION_BUILD_DIR/main.jsbundle.map"Upload dSYMs and source maps
Add a Run Script phase after Bundle React Native code and images. The native dSYM and React Native source map are separate artifacts, so run both upload scripts:
set -e
SERVICES_PLIST="${SRCROOT}/LogDrop-Services.plist"
export LOGDROP_BASE_URL=$(/usr/libexec/PlistBuddy -c "Print :base_url" "$SERVICES_PLIST" 2>/dev/null)
export LOGDROP_API_KEY=$(/usr/libexec/PlistBuddy -c "Print :projects:${PRODUCT_BUNDLE_IDENTIFIER}:app_id" "$SERVICES_PLIST" 2>/dev/null)
export REACT_NATIVE_PATH="${SRCROOT}/../node_modules/react-native"
WITH_ENVIRONMENT="${REACT_NATIVE_PATH}/scripts/xcode/with-environment.sh"
UPLOAD_DSYM_SCRIPT="${PODS_ROOT}/LogDrop/upload_dsym.sh"
UPLOAD_RN_IOS_SCRIPT="${SRCROOT}/../node_modules/@log-drop/react-native/scripts/upload_rn_ios.sh"
/bin/sh "$UPLOAD_DSYM_SCRIPT"
/bin/sh -c "\"$WITH_ENVIRONMENT\" \"$UPLOAD_RN_IOS_SCRIPT\""${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}
${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Resources/DWARF/${PRODUCT_NAME}
${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Info.plist
$(TARGET_BUILD_DIR)/$(EXECUTABLE_PATH)
$(SRCROOT)/.xcode.env.local
$(SRCROOT)/.xcode.env
$(SRCROOT)/LogDrop-Services.plistupload_rn_ios.sh reads base_url and the current bundle identifier's app_id
from LogDrop-Services.plist, matching the native upload_dsym.sh configuration.
LOGDROP_APP_ID or LOGDROP_API_KEY can override the App ID when needed. React
Native source maps are uploaded for Debug and simulator builds as well as Release
device builds.
1.3. Android setup
In your project-level android/build.gradle (or android/settings.gradle),
make sure the LogDrop repositories are included:
allprojects {
repositories {
google()
maven { url "https://artifactory.logdrop.io/repository/android-logdrop-sdk/" }
maven { url "https://artifactory.logdrop.io/repository/logdrop-gradle-plugin/" }
mavenCentral()
}
}Add the plugin classpaths inside the buildscript.dependencies block of android/build.gradle:
dependencies {
classpath "com.android.tools.build:gradle:x.x.x"
classpath "io.logdrop.gradle:plugin:1.1.0"
classpath "io.logdrop.gradle:rnplugin:1.0.4"
}Apply the plugins in android/app/build.gradle to automate ProGuard mapping and React Native JS sourcemap uploads:
apply plugin: "io.logdrop.gradle.plugin"
apply plugin: "io.logdrop.gradle.plugin.rn"Create a file named logdrop-services.json in your android/app directory:
{
"base_url": "https://server.logdrop.io",
"projects": {
"com.yourcompany.yourapp": {
"app_id": "YOUR_LOGDROP_APP_ID"
}
}
}Initialize LogDrop natively in your MainApplication.kt during onCreate() (since Android initializes on the native thread):
override fun onCreate() {
super.onCreate()
val config = LogDropReactNativeConfig.Builder(this)
.appId("YOUR_APP_ID")
.baseUrl("YOUR_BASE_URL")
.logcatEnabled(true)
.build()
LogDropReactNative.initLogDrop(config)
}2. Initialization
Initialize LogDrop before rendering your main React component.
In index.js or App.tsx (early in app startup):
import { AppRegistry } from 'react-native';
import App from './App';
import { LogDrop, LogDropConfigBuilder } from '@log-drop/react-native';
async function bootstrap() {
const config = new LogDropConfigBuilder()
.setAppId('YOUR_APP_ID')
.setBaseUrl('YOUR_BASE_URL') // Optional: for self-hosted LogDrop
.setLoggingEnabled(true)
.build();
LogDrop.init(config);
AppRegistry.registerComponent('YourApp', () => App);
}
bootstrap();The native iOS and Android SDKs handle native crashes; the React Native layer adds JS error capture on top.
3. LogDropConfig Overview
interface LogDropConfig {
appId: string;
baseUrl: string;
isLoggingEnabled: boolean;
defaultSDKDisabled: boolean;
pushAppGroupSuiteName?: string; // iOS only
}Use new LogDropConfigBuilder() to construct the configuration options and pass the result to LogDrop.init(config).
4. Crash Tracking
-
Native iOS/Android crashes – handled by the underlying native SDKs. 2. JavaScript errors – captured and reported automatically on calling
LogDrop.init(...)via global error hooks.On iOS, native frames require the dSYM and JavaScript frames require the React Native source map. Configure both uploads in the iOS setup. On Android, the LogDrop Gradle plugins upload ProGuard/R8 mappings and React Native source maps.
5. Logging Methods
Use the LogDrop logging methods anywhere in your React Native code.
5.1. Basic logging
import { LogDrop } from '@log-drop/react-native';
LogDrop.e('Payment', 'Payment failed'); // Error
LogDrop.w('Network', 'Slow network'); // Warning
LogDrop.i('Auth', 'User logged in'); // Info
LogDrop.d('Parser', 'Parsing response'); // Debug
// With flow
import { LogFlow } from '@log-drop/react-native';
const flow = new LogFlow(
'SuccessTransaction',
transactionId,
new Map([
['amount', '149.90'],
['currency', 'TRY']
])
);
LogDrop.i('Transaction', 'Transaction completed successfully.', flow);5.3. Sending logs
Logs are buffered locally on the device.
To force an upload to the server:
LogDrop.sendLogs();- Schedules a background job that runs approximately 60 seconds later.
- If a job is already scheduled or running, additional calls do not create new jobs.
6. LogFlow
LogFlow allows you to group related logs into a single business flow or transaction.
const checkoutFlow = new LogFlow(
'CartCheckout',
checkoutId,
new Map([
['itemsCount', String(items.length)],
['total', totalPrice.toFixed(2)],
['currency', 'TRY']
])
);
LogDrop.i('Checkout', 'Checkout started.', checkoutFlow);
LogDrop.i('Checkout', 'Payment screen opened.', checkoutFlow);
LogDrop.i('Checkout', 'Checkout completed.', checkoutFlow);In the LogDrop panel you can filter and analyze logs by flowName and flowId.
7. Push Notification Integration
The React Native SDK does not install a push provider. Keep the application's
existing provider and forward its token and messages identified by
LogDrop.isLogDropPush(...) to the bridge.
7.1. Android with React Native Firebase
With @react-native-firebase/messaging, register the background handler at module
scope. Forward LogDrop messages from both foreground and background handlers, and
register both the current FCM token and future token updates.
import {
getMessaging,
getToken,
onMessage,
onTokenRefresh,
setBackgroundMessageHandler,
type FirebaseMessagingTypes,
} from '@react-native-firebase/messaging';
import { LogDrop } from '@log-drop/react-native';
const messaging = getMessaging();
const logDropData = (
data: FirebaseMessagingTypes.RemoteMessage['data']
): Record<string, string> =>
Object.fromEntries(
Object.entries(data ?? {}).filter(
(entry): entry is [string, string] => typeof entry[1] === 'string'
)
);
async function forwardLogDropMessage(
message: FirebaseMessagingTypes.RemoteMessage
) {
const data = logDropData(message.data);
if (await LogDrop.isLogDropPush(data)) {
LogDrop.onRemoteMessageReceived(data);
}
}
setBackgroundMessageHandler(messaging, forwardLogDropMessage);
export async function registerLogDropPushHandlers() {
onTokenRefresh(messaging, LogDrop.onNewFcmPushToken);
onMessage(messaging, forwardLogDropMessage);
LogDrop.onNewFcmPushToken(await getToken(messaging));
}Import the module during startup and call registerLogDropPushHandlers() after
LogDrop.init(config). For a native FCM or HMS integration, use the equivalent
methods exposed by LogDropReactNative.
7.2. iOS APNs Forwarding
iOS does not require a Firebase dependency. Forward the APNs token and remote
notifications from AppDelegate:
import LogDropSDK
override func application(
_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
) {
LogDrop.onNewApnsToken(apnsToken: deviceToken)
}
override func application(
_ application: UIApplication,
didReceiveRemoteNotification userInfo: [AnyHashable: Any],
fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void
) {
LogDrop.onRemoteMessageReceived(userInfo)
completionHandler(.newData)
}If the application's messaging library exposes the APNs token as hexadecimal text,
forward it from JavaScript with LogDrop.onNewApnsToken(token) instead.
7.3. iOS Notification Service Extension
Complete the iOS Notification Service Extension and App Group setup. Pass the same App Group identifier from the React Native configuration:
const config = new LogDropConfigBuilder()
.setAppId('YOUR_APP_ID')
.setBaseUrl('YOUR_BASE_URL')
.setPushAppGroupSuiteName('group.com.yourcompany.yourapp')
.build();Use the matching value in the extension configuration:
import LogDropSDK
final class NotificationService: LogDropNotificationServiceExtension {
override func logDropConfiguration() -> LogDropConfig? {
LogDropConfig.Builder()
.setAppId("YOUR_APP_ID")
.setBaseUrl("YOUR_BASE_URL") // Optional: for self-hosted LogDrop
.setPushAppGroupSuiteName("group.com.yourcompany.yourapp")
.build()
}
}7.4. Show a Pending Push Action
Ask LogDrop to present a queued in-app popup or internal-browser action when the application starts and whenever it becomes active:
import { useEffect } from 'react';
import { AppState } from 'react-native';
useEffect(() => {
const showPendingPushAction = () => {
void LogDrop.showPendingPushPopup();
};
showPendingPushAction();
const subscription = AppState.addEventListener('change', state => {
if (state === 'active') {
showPendingPushAction();
}
});
return () => subscription.remove();
}, []);8. Deep Links
Keep routing links through the application's existing React Native navigation. After the application receives and resolves a URL, forward that URL once to LogDrop:
LogDrop.trackDeepLink(url);Use the same call for initial and already-running link deliveries.
9. User Identification (UUID Customization)
By default, logs are tied to a device identifier. To associate logs with your own user ID:
LogDrop.userUpdate('user-1234@example.com');-
Email address
-
Internal customer ID
-
Other application-specific user ID
All subsequent logs will be associated with this user in the LogDrop panel.
10. Custom Events
Use custom events to track application-specific actions that are not covered by LogDrop's built-in events. Send a stable event name together with optional JSON-compatible properties.
10.1. Track a Custom Event
LogDrop.trackCustomEvent('purchase_completed', {
coupon_code: 'SUMMER10',
amount: 49.9,
item_count: 2,
is_first_order: true,
});Properties are optional. To track an event without properties:
LogDrop.trackCustomEvent('onboarding_completed');Provide only the readable event name and properties. Event and property codes shown in the panel are managed by LogDrop.
10.2. Supported Property Values
Custom properties may contain strings, numbers, booleans, null, nested objects, and arrays. Object keys must be strings.
LogDrop.trackCustomEvent('product_viewed', {
sku: 'LD-100',
viewed_at: new Date().toISOString(),
product: {
name: 'LogDrop Hoodie',
price: 79.95,
},
categories: ['merch', 'hoodies'],
variants: [
{ color: 'black', size: 'M' },
{ color: 'green', size: 'L' },
],
campaign: null,
});React Native's native-module bridge accepts JSON-compatible values. Convert
JavaScript Date instances to ISO-8601 strings before passing them. Nested objects
and arrays remain structured values.
10.3. Naming and Property Types
- Use stable and consistent names. For example, do not alternate between
purchase_completedandpurchaseCompletedfor the same event. - Do not put IDs, timestamps, or other dynamic values in the event name. Add them as properties instead.
- Do not use the name of a LogDrop default event for a custom event.
- Keep each property's type stable. For example, always send
amountas a number rather than sometimes sending a number and sometimes a string. - Reusing the same event name updates the same custom event schema. Changing the name creates a different custom event.
If a property is later sent with a different type, LogDrop keeps the event but marks the property as a type conflict in the panel. Type conflict tracking helps find integration mistakes; it should not be used as a replacement for a stable event contract.
10.4. Limits and Validation
- Event names can contain up to 128 characters.
- Property names can contain up to 128 characters.
- One event can contain up to 100 top-level properties.
- The complete properties JSON can contain up to 16 KB in UTF-8, including property names, primitive values, nested objects, and arrays.
- Event names and property names cannot be empty.
- Property values must be JSON-compatible.
If validation fails, the native SDK rejects the complete event and writes the reason to the SDK log. Names, properties, and payloads are never silently truncated.
10.5. Panel Behavior
No custom event definition is required before tracking. After the first valid event reaches LogDrop, the Events page shows the event, its generated code, observed properties, property types, and any type conflicts. You can then use the event in event details and Event Analytics funnels.
11. Custom User Attributes
Custom user attributes let you attach stable profile information to the current
LogDrop device and use it for segment-based push targeting in the panel. Call these
APIs after LogDrop.init(config) has completed.
11.1. Set or Update Attributes
LogDrop.setCustomAttributes({
plan_type: 'premium',
country: 'TR',
preferred_language: 'tr',
});The update is an additive upsert. New keys are added and existing keys receive the new value, while attributes omitted from the call remain unchanged. Valid changes are persisted by the native SDK and synchronized with LogDrop automatically.
11.2. Remove an Attribute
LogDrop.removeCustomAttribute('plan_type');Removing a key also synchronizes the deletion with LogDrop, so the previous value is no longer available for future segment targeting.
11.3. Limits and Validation
- Attributes must be provided as a
Record<string, string>. - A device can have up to 30 custom attributes in total.
- Keys must contain only letters, numbers, underscores (
_), or hyphens (-). - Keys can contain up to 64 characters.
- Values must be non-blank strings containing up to 256 characters.
- If one entry in a call is invalid, the native SDK rejects the complete update.
- If the merged result would exceed 30 keys, the previous attribute set remains unchanged.
Custom user attributes are different from LogFlow.customAttributes. User attributes
describe a device for audience targeting, while flow attributes add context only to the
logs recorded with that LogFlow.
11.4. Use Attributes in the Panel
After the device synchronizes, open Push Notification → Send Push, select Segment under Recipients, and build a filter with the attribute key. See Segment Targeting with Custom Attributes.
12. Troubleshooting
- Ensure
LogDrop.init(config)is called before logging or sending logs. - Confirm that your App ID and
baseUrl(if used) are correctly configured. - On iOS, make sure
pod installhas been run, the workspace is opened in Xcode, and the upload phase runs after Bundle React Native code and images. - If an iOS JavaScript crash is not symbolicated, confirm that
main.jsbundle.mapis generated and that the build log containsReact Native iOS source map upload completed. - If the iOS upload cannot resolve the project, confirm that
LogDrop-Services.plistcontains anapp_idfor the exactPRODUCT_BUNDLE_IDENTIFIER. - On Android, verify that the LogDrop Maven repository is configured, plugins are applied, and Gradle sync succeeds.
- Confirm that custom event names do not match LogDrop default event names.
- Check native SDK logs when a custom event is missing; invalid names, properties, or oversized payloads are rejected locally.
- Check native SDK logs when custom user attributes are missing; invalid updates and updates exceeding 30 keys are rejected locally.
- If using FCM:
- Check that Firebase is initialized correctly.
- Ensure background handlers are registered early (before app mount).
- Confirm that
isLogDropPush,onNewFcmPushToken, andonRemoteMessageReceivedare being called.
.png)