npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@luciq/react-native

v19.10.1

Published

Luciq is the Agentic Observability Platform built for Mobile.

Readme

npm version npm downloads Platform License

Our intelligent AI agents help you capture rich, contextual data for every issue, including full session replays, console logs, and detailed network requests, to proactively detect, prioritize, and resolve problems automatically.

Ship faster, deliver frustration-free user sessions, and focus on building what matters.


Table of Contents


Requirements

  • React Native >= 0.72.3
  • iOS >= 13.4
  • Android minSdkVersion >= 21

Installation

  1. Install the package:

    npm install @luciq/react-native
    # or
    yarn add @luciq/react-native
  2. Expo only. Add the Luciq config plugin to app.json:

    {
      "expo": {
        "plugins": [
          [
            "@luciq/react-native",
            {
              "addScreenRecordingBugReportingPermission": true
            }
          ]
        ]
      }
    }

    addScreenRecordingBugReportingPermission is optional — when true, the plugin adds the iOS microphone & photo-library usage descriptions and the Android FOREGROUND_SERVICE_MEDIA_PROJECTION permission required for screen recording in bug reports.

  3. iOS only. Install CocoaPods:

    cd ios && pod install && cd ..

Initializing Luciq

Call Luciq.init once, as early as possible — at the top of your entry file (index.js or App.tsx), outside any component. InvocationEvent is a named export, not a property on the default Luciq namespace.

import Luciq, { InvocationEvent } from '@luciq/react-native';

Luciq.init({
  token: 'APP_TOKEN',
  invocationEvents: [InvocationEvent.shake],
});

You can combine multiple invocation events:

Luciq.init({
  token: 'APP_TOKEN',
  invocationEvents: [
    InvocationEvent.shake,
    InvocationEvent.screenshot,
    InvocationEvent.floatingButton,
  ],
});

Available InvocationEvent values: shake, screenshot, twoFingersSwipe, floatingButton, none.

Find your app token in your Luciq dashboard under Settings → SDK Integration.

iOS Usage Descriptions

Luciq needs microphone access to capture audio during screen recordings, and photo-library access to let users attach images to bug reports. Apple rejects apps that omit usage descriptions for either, so add the following keys to your app's Info.plist:

  • NSMicrophoneUsageDescription
  • NSPhotoLibraryUsageDescription

Suggested copy:

  • "<app name> needs microphone access to record audio with screen recordings attached to bug reports."
  • "<app name> needs photo-library access to attach images to bug reports."

The permission prompts only appear when a user actually starts a screen recording or attaches a photo from the Luciq UI.

Source Map Uploads for Crash Reports

For your app crashes to show fully symbolicated stack traces, the build scripts in @luciq/react-native will generate and upload source maps to your dashboard on release builds. The uploader reads your app token from the Luciq.init({ token: 'YOUR_APP_TOKEN' }) call in JavaScript.

If your token is defined as a constant or imported from elsewhere, override the lookup with environment variables:

| Variable | Purpose | | --------------------------------- | ------------------------------------- | | LUCIQ_APP_TOKEN | App token used for the upload | | LUCIQ_APP_VERSION_NAME | Overrides the inferred versionName | | LUCIQ_APP_VERSION_CODE | Overrides the inferred versionCode | | LUCIQ_SOURCEMAPS_UPLOAD_DISABLE | Set to TRUE to skip the upload step |

Network Logging

Network logging is enabled by default. It intercepts fetch and XMLHttpRequest calls and attaches them to outgoing reports. Disable it with:

import { NetworkLogger } from '@luciq/react-native';

NetworkLogger.setEnabled(false);

Repro Steps

Luciq Repro Steps record the screens a user visits. Each screen is attached to a bug report when it's sent. Repro Steps are enabled by default.

React Navigation

v5+ — pass Luciq.onStateChange to your NavigationContainer:

import { NavigationContainer } from '@react-navigation/native';
import Luciq from '@luciq/react-native';

<NavigationContainer onStateChange={Luciq.onStateChange}>{/* ... */}</NavigationContainer>;

v4 and below — wire Luciq.onNavigationStateChange to the root app:

export default () => <App onNavigationStateChange={Luciq.onNavigationStateChange} />;

React Native Navigation (Wix)

Register Luciq.componentDidAppearListener:

import { Navigation } from 'react-native-navigation';
import Luciq from '@luciq/react-native';

Navigation.events().registerComponentDidAppearListener(Luciq.componentDidAppearListener);

Manual screen reporting

For custom navigation, report screen changes yourself:

Luciq.reportScreenChange('CheckoutScreen');

Disabling Repro Steps

import Luciq, { ReproStepsMode } from '@luciq/react-native';

Luciq.setReproStepsConfig({ all: ReproStepsMode.disabled });

ReproStepsMode values: enabled, enabledWithNoScreenshots, disabled.

Custom Spans (APM)

Custom spans let you manually instrument arbitrary code paths for performance tracking — useful for operations that aren't covered by the automatic instrumentation.

Start / end a span

import { APM } from '@luciq/react-native';

const span = await APM.startCustomSpan('Load User Profile');

if (span) {
  try {
    await loadUserProfile();
  } finally {
    await span.end();
  }
}

Record a completed span

import { APM } from '@luciq/react-native';

const start = new Date(Date.now() - 1500);
const end = new Date();

await APM.addCompletedCustomSpan('Cache Lookup', start, end);

Behavior

  • Limit: up to 100 concurrent spans at a time.
  • Name length: truncated to 150 characters; empty names are rejected.
  • Timestamps: endDate must be after startDate; otherwise the span is rejected.
  • Idempotent: calling span.end() more than once is safe.
  • Gating: spans are only created when the SDK is initialized, APM is enabled, and the custom-spans feature is enabled for your account.

API reference

APM.startCustomSpan(name: string): Promise<CustomSpan | null>

Starts a custom span. Returns the span object, or null if the span couldn't be created (e.g. feature disabled, span cap reached, invalid name).

CustomSpan.end(): Promise<void>

Ends the span and reports it. Idempotent.

APM.addCompletedCustomSpan(name: string, startDate: Date, endDate: Date): Promise<void>

Records a span whose start and end times are already known.

TypeScript

The package ships with type definitions. The public surface is exposed as:

  • Luciq (default export) — top-level SDK actions: init, onStateChange, onNavigationStateChange, componentDidAppearListener, reportScreenChange, setReproStepsConfig, and many more.
  • Named modules: APM, BugReporting, CrashReporting, FeatureRequests, NetworkLogger, Replies, SessionReplay, Surveys.
  • Named enums: InvocationEvent, ReproStepsMode, LogLevel, NetworkInterceptionMode, Locale, ColorTheme, WelcomeMessageMode, ExtendedBugReportMode, NonFatalErrorLevel, and more.
  • Named types: LuciqConfig, ThemeConfig, NetworkData, Survey, SessionMetadata.
import Luciq, {
  APM,
  BugReporting,
  CrashReporting,
  InvocationEvent,
  NetworkLogger,
  ReproStepsMode,
  type LuciqConfig,
} from '@luciq/react-native';

Adding a new feature

The library supports both the old bridge architecture and the new architecture (TurboModules) from a single source tree. Adding a new API — either a new method on an existing module or a brand-new module — requires touching the JS layer, the Codegen spec, and both native platforms in lockstep so that the types stay aligned.

Adding a method to an existing module

  1. Codegen spec — add the method signature to src/specs/Native<Module>.ts. Signatures here must use Codegen-compatible types (boolean, string, number / double, Array<...>, Object, Promise<T>, void). Avoid int — use double. Callbacks for spec methods are typed as (value: Object) => void.
  2. JS native wrapper — mirror the method on the NativeModule interface in src/native/Native<Module>.ts. This is the richly-typed surface (enum types, unions) that the JS modules consume; the spec is the Codegen-safe subset.
  3. JS module — expose the public API in src/modules/<Module>.ts, calling through Native<Module>.<method>(...).
  4. Android — implement the method in android/src/main/java/ai/luciq/reactlibrary/RNLuciq<Module>Module.java. The module extends Native<Module>Spec; annotate with @ReactMethod and match the spec's parameter types exactly (e.g. double not int, Promise where the spec returns Promise<T>).
  5. iOS — implement the method in ios/RNLuciq/Luciq<Module>Bridge.mm using RCT_EXPORT_METHOD. The bridge file extension is .mm (Objective-C++) so the same source compiles on both architectures.
  6. Tests — add coverage in test/modules/<Module>.spec.ts and android/src/test/java/ai/luciq/reactlibrary/RNLuciq<Module>ModuleTest.java.

Adding a brand-new module

In addition to the steps above, register the new module in each arch-specific location:

  1. Codegen spec — create src/specs/Native<Module>.ts and export the module via TurboModuleRegistry.get<Spec>('LCQ<Module>'). Keep the LCQ prefix — it must match the iOS RCT_EXPORT_MODULE name and the Android NAME constant.
  2. JS native wrapper — create src/native/Native<Module>.ts with a fallback: (TurboSpec ?? ReactNativeModules.LCQ<Module>) as unknown as <Module>NativeModule. Add the module to the LuciqNativePackage interface in src/native/NativePackage.ts.
  3. JS module and public export — create src/modules/<Module>.ts and re-export it from src/index.ts.
  4. Android Codegen spec — add android/src/oldarch/java/ai/luciq/reactlibrary/Native<Module>Spec.java extending ReactContextBaseJavaModule, with public static final String NAME = "LCQ<Module>". The newarch variant is generated into build/generated/source/codegen/java by React Gradle Plugin at build time, so nothing is hand-authored under android/src/newarch/.
  5. Android module — create android/src/main/java/ai/luciq/reactlibrary/RNLuciq<Module>Module.java extending Native<Module>Spec, and register it in RNLuciqReactnativePackage.java (which extends TurboReactPackage): add a case "LCQ<Module>" returning a new instance in getModule(...), and a matching ReactModuleInfo entry in getReactModuleInfoProvider(). The isTurboModule flag is driven by BuildConfig.IS_NEW_ARCHITECTURE_ENABLED, so the same registration works on both architectures.
  6. iOS bridge — create ios/RNLuciq/Luciq<Module>Bridge.h / .mm. Use RCT_EXPORT_MODULE(LCQ<Module>) so the name resolves on both architectures.

Running Codegen locally

Codegen runs automatically during the example app's build. To regenerate manually from the library root:

cd examples/default/android && ./gradlew generateCodegenArtifactsFromSchema
cd examples/default/ios && RCT_NEW_ARCH_ENABLED=1 pod install

If the JS spec and the native implementation disagree on a type, Codegen will fail the build with a mismatch error — that's the signal to bring the three layers back in sync.

Need Help?

🌐 Visit our website • 📖 Read the docs • 💬 Get help

Contact Us

Primary Contact Email: [email protected]

LinkedIn: linkedin.com/company/luciq