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

react-native-inappbrowser-nitro

v3.0.2

Published

react-native-inappbrowser-nitro is a react native package built with Nitro

Downloads

9,843

Readme

react-native-inappbrowser-nitro

Native in-app browser for React Native, powered by Nitro Modules.

npm version npm downloads bundle size license CI CI

Installation · Quick start · API · Options · FAQ · Changelog


⚡ Why this library?

| | | |---|---| | ⚡ JSI bindings | Direct native calls through Nitro Modules. No JSON serialization, no scheduler hops. | | 🎯 Right primitive per platform | SFSafariViewController on iOS, Chrome Custom Tabs on Android. Not a WKWebView reimplementation. | | 🔐 OAuth built in | openAuth wraps ASWebAuthenticationSession with ephemeral sessions and redirect interception. | | 🪝 Hook + functions | useInAppBrowser() for React state, named exports for everything else. | | 🧩 TypeScript first | Discriminated result types, as const enums, full JSDoc. | | 📦 Tree-shakeable | "sideEffects": false, ESM build, lazy native module init. |


📋 Requirements

| | Minimum | Tested up to | |---|---|---| | React Native | 0.75 (New Architecture) | 0.85 | | iOS | 15.1 | 26.2 | | Android | API 23 (Android 6) | API 36 (Android 16) | | react-native-nitro-modules | 0.35 | 0.35.4 |

[!IMPORTANT] This library requires the React Native New Architecture and does not work in Expo Go. Use Expo prebuild / dev clients instead.


📦 Installation

yarn add react-native-inappbrowser-nitro react-native-nitro-modules
npm install react-native-inappbrowser-nitro react-native-nitro-modules
pnpm add react-native-inappbrowser-nitro react-native-nitro-modules
bun add react-native-inappbrowser-nitro react-native-nitro-modules

iOS

cd ios && pod install

Android

Autolinking handles everything. No manual MainApplication edits.

[!NOTE] Release builds with ProGuard/R8 need this rule in android/app/proguard-rules.pro:

# react-native-inappbrowser-nitro
-keep class com.inappbrowsernitro.** { *; }

Without it, you'll see Couldn't find class 'com/inappbrowsernitro/HybridInappbrowserNitro'.


🚀 Quick start

Hook

import { useInAppBrowser } from 'react-native-inappbrowser-nitro/hooks'

function DocsButton() {
  const { open, isLoading, error } = useInAppBrowser()

  return (
    <Pressable
      disabled={isLoading}
      onPress={() => open('https://nitro.margelo.com')}
    >
      <Text>{isLoading ? 'Opening…' : 'Open docs'}</Text>
      {error && <Text style={{ color: 'red' }}>{error.message}</Text>}
    </Pressable>
  )
}

The hook guards state updates after unmount and returns stable open/openAuth references via useCallback.

Imperative

import { isAvailable, open } from 'react-native-inappbrowser-nitro'

if (await isAvailable()) {
  const result = await open('https://github.com', {
    preferredBarTintColor: { light: '#FFFFFF', dark: '#000000' }, // iOS
    toolbarColor: { light: '#FFFFFF', dark: '#000000' },         // Android
    readerMode: true,
  })

  if (result.type === 'success') {
    console.log('Opened', result.url)
  }
}

OAuth / SSO

import { openAuth } from 'react-native-inappbrowser-nitro'

const result = await openAuth(
  'https://example.com/oauth/authorize?client_id=…&redirect_uri=myapp%3A%2F%2Fcb',
  'myapp://cb',
  {
    ephemeralWebSession: true,       // iOS: don't share Safari cookies
    enableEdgeDismiss: false,        // iOS: block swipe-to-dismiss during auth
    forceCloseOnRedirection: true,   // Android: close tab on redirect match
  }
)

if (result.type === 'success' && result.url) {
  const code = new URL(result.url).searchParams.get('code')
  // exchange code for token
}

📖 API

All exports come from the package root unless noted. Every function returns a Promise.

| Export | Signature | Description | |---|---|---| | isAvailable | () => Promise<boolean> | true when a compliant Safari/Custom Tabs runtime is reachable. Always true on iOS; on Android requires a Custom Tabs–capable browser. | | open | (url, options?) => Promise<InAppBrowserResult> | Present an in-app browser. Resolves when the user dismisses or the system closes it. | | openAuth | (url, redirectUrl, options?) => Promise<InAppBrowserAuthResult> | Run an authentication session. Resolves the moment native code intercepts a navigation matching redirectUrl. | | close | () => Promise<void> | Dismiss the current browser. No-op when none is presented. | | closeAuth | () => Promise<void> | Cancel an in-flight openAuth session. | | useInAppBrowser | () => UseInAppBrowserReturn | Hook wrapping open/openAuth with isLoading + error state. Exported from react-native-inappbrowser-nitro/hooks. |

Result shape

type BrowserResultType = 'cancel' | 'dismiss' | 'success'

interface InAppBrowserResult {
  type: BrowserResultType
  url?: string      // final URL captured by the browser session
  message?: string  // human-readable reason on `dismiss`
}

Errors

open and openAuth reject with an Error when the URL is empty, missing a scheme, or uses a denied scheme (javascript:, data:, vbscript:). These checks run in JS before the call crosses JSI.


⚙️ Options

open and openAuth accept one options object. Platform-only fields are ignored on the other platform.

iOS

| Option | Type | Default | Notes | |---|---|---|---| | dismissButtonStyle | 'done' \| 'close' \| 'cancel' | 'done' | Toolbar dismiss button label. | | preferredBarTintColor | DynamicColor | system | Safari toolbar background hint. iOS 26 Liquid Glass may ignore it. | | preferredControlTintColor | DynamicColor | system | Safari control tint hint. iOS 26 may adapt it for contrast. | | preferredStatusBarStyle | 'default' \| 'lightContent' \| 'darkContent' | system | Status bar appearance while presented. | | readerMode | boolean | false | iOS only. Ask Safari to enter Reader Mode if the page supports it; Android Custom Tabs ignore this option. | | animated | boolean | true | Animate present/dismiss. | | modalPresentationStyle | ModalPresentationStyle | 'automatic' | UIKit modal style. | | modalTransitionStyle | ModalTransitionStyle | 'coverVertical' | UIKit transition. Use 'partialCurl' only with 'fullScreen'. | | modalEnabled | boolean | true | Present modally instead of pushing onto a navigation stack. | | enableBarCollapsing | boolean | false | Collapse toolbar on scroll. | | ephemeralWebSession | boolean | false | openAuth only: do not persist cookies/credentials. | | enableEdgeDismiss | boolean | true | Allow swipe-from-edge to dismiss. | | overrideUserInterfaceStyle | 'unspecified' \| 'light' \| 'dark' | 'unspecified' | Force light/dark while presented. | | formSheetPreferredContentSize | { width, height } | UIKit | Preferred form-sheet size. UIKit may adapt or ignore it on iPhone. |

Android

| Option | Type | Default | Notes | |---|---|---|---| | showTitle | boolean | false | Show page title under the URL bar. | | toolbarColor | DynamicColor | browser default | Top toolbar background. | | secondaryToolbarColor | DynamicColor | browser default | Bottom toolbar background. | | navigationBarColor | DynamicColor | system | API 27+. | | navigationBarDividerColor | DynamicColor | system | API 28+. | | enableUrlBarHiding | boolean | false | Hide URL bar on scroll. | | enableDefaultShare | boolean | false | Show share menu item. Use shareState for finer control. | | shareState | 'default' \| 'on' \| 'off' | 'default' | Override share menu visibility. | | colorScheme | 'system' \| 'light' \| 'dark' | 'system' | Custom Tab theme hint. | | headers | Record<string, string> | {} | HTTP headers on initial request. | | forceCloseOnRedirection | boolean | false | Auto-close tab when redirect URL matches. | | hasBackButton | boolean | false | Show back arrow instead of X. | | browserPackage | string | auto | Pin to a specific browser, e.g. com.android.chrome. | | showInRecents | boolean | true | Keep the tab in Android Recents after closing. | | includeReferrer | boolean | false | Send the host app package as Referrer. | | instantAppsEnabled | boolean | true | Allow Instant Apps to handle the URL. | | enablePullToRefresh | boolean | false | Enable swipe-to-refresh. | | enablePartialCustomTab | boolean | false | Show a resizable bottom sheet on Android 13+. | | animations | BrowserAnimations | system | Custom enter/exit animation resource names. |

Dynamic colors

Color options accept a DynamicColor object:

interface DynamicColor {
  base?: string // fallback
  light?: string // light mode
  dark?: string // dark mode
  highContrast?: string // increased contrast, where supported
}

Each value must be #RRGGBB or #AARRGGBB. Missing mode-specific values fall back to base, then the system default.


🔧 Platform notes

iOS 26 Liquid Glass

iOS 26 renders SFSafariViewController chrome with system Liquid Glass. Apple controls the final toolbar material, contrast, and legibility:

  • preferredBarTintColor can have little or no visible effect.
  • preferredControlTintColor may be adapted by the system.
  • formSheetPreferredContentSize is only a UIKit preference and is commonly adapted on iPhone.

The properties are still forwarded for iOS versions and contexts that honor them.

If pixel-exact browser chrome matters, use a WKWebView-based screen for non-auth flows. Do not use WKWebView for OAuth; it lacks Safari's process isolation, cookie sharing, autofill, and many providers forbid it.

Android browser fallback

Android prefers Chrome Custom Tabs. On devices without a Custom Tabs–capable browser the system shows a chooser via Intent.ACTION_VIEW, and option fields like toolbarColor are silently ignored.


❓ FAQ

SFSafariViewController and Chrome Custom Tabs share the system Safari/Chrome session — cookies, autofill, content blockers, and password autofill from iCloud Keychain / Google Password Manager. They run in a separate process from your app, so the host app cannot read page content. Most OAuth providers require this. WKWebView offers none of it.

Yes, in Expo prebuild / dev client projects. It does not work in Expo Go (managed workflow) because Nitro requires native compilation.

No. Nitro Modules require the New Architecture (newArchEnabled=true on Android, Fabric/TurboModule autolinking on iOS).

The default emulator image ships without a Custom Tabs–capable browser. Install Chrome from the Play Store image, or use a Pixel system image with Play Services preinstalled.

You're calling open instead of openAuth. openAuth uses ASWebAuthenticationSession, the only iOS API that can intercept a redirect URL programmatically. open uses SFSafariViewController, which cannot.

The URL was rejected by the JS-side validator (empty / missing scheme / denied scheme). Check result.message for the reason. Native-side logs are also visible in Xcode / Logcat.


🤝 Contributing

Contributions welcome. The library is small and well-tested — a good place to land your first React Native PR.

Found a bug or have a feature request? Open an issue.

git clone https://github.com/mCodex/react-native-inappbrowser-nitro
cd react-native-inappbrowser-nitro
yarn install
yarn codegen     # regenerate Nitro bindings + build
yarn typecheck
yarn lint

Run the example app:

cd example
yarn ios       # or: yarn android

A pre-commit hook (Husky + lint-staged + Biome) auto-formats staged files. CI runs on iOS (macos-26, Xcode 26.2) and Android (ubuntu-latest, JDK 21).


📄 License

MIT © Mateus Andrade