React Native (Expo)
This is not a full mobile wallet SDK. It is a compact Expo demo that shows how an app can connect to Nostr Wallet Connect, read balance and pay an invoice while dealing with the awkward mobile runtime pieces.
Start with the exact repository
React Native (Expo) refers here to `getAlby/nwc-react-native-expo`, not to React Native as a framework and not to Expo as a general app platform. The repository description is narrow and useful: it is an example of using the Alby JS SDK, specifically Nostr Wallet Connect, in a React Native Expo project.
That matters because a lot of NWC pages can sound abstract until you reach a runtime boundary. Browser examples can assume Web Crypto, popups, `window` behavior and web extension habits. Server examples can assume Node, a file system and a long-lived process. A mobile Expo app sits in the middle: JavaScript runs in a React Native environment, user authorization needs a native-feeling flow, and secrets must not be treated like harmless form fields.
The demo is therefore valuable because it is small enough to read and concrete enough to test. It does not try to be a universal wallet kit. It shows one app screen, one connect button, one paste box, one balance call and one payment call. For a builder, that is often the fastest way to see what breaks when a web-oriented NWC SDK is asked to run inside a mobile shell.
Read it with the right expectation. It is a showcase, not a finished integration layer. If your goal is to ship a user-facing mobile product that can authorize payments, this repository should be treated as a working sketch and a checklist generator rather than the complete answer.
Repository state checked today
GitHub metadata checked on June 15, 2026 showed the repository as public, non-archived and created on November 13, 2023. The default branch is `master`. The repository API reported TypeScript as the primary language, five stars, zero forks, one open issue and no license metadata.
The visible repository shape is simple. The top level includes `App.tsx`, `applyGlobalPolyfills.ts`, `app.json`, `eas.json`, `package.json`, `tsconfig.json`, `webln-types.d.ts`, `yarn.lock`, assets and a short README. GitHub's language API showed TypeScript making up nearly all of the code, with a small JavaScript remainder.
The commit history is also small. The latest commit in the checked API response was `chore: update dependencies` from December 6, 2024. Earlier November 2023 commits added the README, a `sendPayment` example, a Connect with Alby button, a demo video note and an Android safe-area fix. There were no published releases or tags to pin.
That combination should shape how you depend on it. If you copy the idea into an app, pin the exact commit you reviewed. Do not assume a hidden release process, formal changelog or compatibility matrix exists elsewhere. The repository is useful precisely because its moving parts are visible.
What the README promises
The README gives the shortest possible product brief. It says to run `yarn start` or `yarn start:tunnel`. It then lists three features: connect with Alby or paste a NWC URL, get balance and pay an invoice. That is the entire user-facing demo surface.
Those three bullets are enough to cover the important NWC arc. A mobile app needs a way to acquire a scoped wallet connection. It needs a read method to prove that the connection is alive and authorized. It needs a payment method to prove that wallet authority can move from a Lightning invoice through Nostr relays to a wallet service and back.
The README does not promise secure storage, background sessions, a wallet selector, error recovery, deep linking, push notifications, app-store readiness, production budgets or a full WebLN implementation. That omission is not a flaw in a demo. It is a boundary line for readers.
The demo video linked from the README is useful as a behavior clue, but the code is more important than the clip. The code tells you what the app is actually doing: which SDK surface it calls, how it performs authorization, which polyfills it installs and what state it keeps in memory.
The app has two connection paths
`App.tsx` exposes two ways to reach a wallet. The plain path is a text input where the user pastes a NWC URL. When `nwcUrl` exists, the app constructs `new webln.NostrWebLNProvider({ nostrWalletConnectUrl: nwcUrl })`, calls `enable()`, calls `getBalance()` and stores the provider in React state.
The second path is the Connect with Alby button. It calls `webln.NostrWebLNProvider.withNewSecret`, asks the SDK for an authorization URL with the name `React Native NWC demo`, saves the pending NWC URL and opens a WebView pointing at the authorization page. When the WebView reports `nwc:success`, the app closes the authorization screen and uses the pending connection.
These two paths are a smart demo choice. The paste box is blunt, testable and useful when you already have a NWC string from a wallet such as Alby Hub or another service. The authorization path is closer to a consumer flow because it lets the wallet issue the connection after the user approves it.
For production, the difference becomes product work. A paste box is easy for builders and fragile for normal users. An authorization WebView is smoother, but it still needs a clear return path, cancellation handling, permission display, trust indicators and secure storage after the connection is created.
What the WebView handoff does
When `nwcAuthUrl` is present, the app renders `react-native-webview`. The WebView loads the Alby authorization URL and injects a small script that assigns `window.opener = window`, listens for `message` events and forwards `event.data?.type` to React Native via `window.ReactNativeWebView.postMessage`.
That injected script is revealing. The code comment says the `window.opener` workaround should be removed once NWC posts to `window`. In other words, the demo is bridging a web authorization pattern into a mobile WebView environment where browser-window assumptions do not map cleanly.
The native side parses the WebView message and looks for the `nwc:success` type. On success it clears the authorization URL and moves the pending NWC URL into active state. That triggers the same provider setup as a pasted connection string.
This is the part mobile developers should slow down over. Authorization is not just a URL open. It is a boundary between wallet UI, app state and a secret-bearing connection string. A polished app needs cancellation states, loading states, failed authorization states, malformed message handling, origin checks where possible and a clear way to prevent stale pending credentials from being accidentally reused.
Balance and payment are deliberately small
After a connection is active, the demo calls `getBalance()` and displays the balance in sats. It then uses `LightningAddress` from `@getalby/lightning-tools` to fetch `hello@getalby.com`, asks for a one-satoshi invoice and stores the resulting payment request.
The payment button calls `nostrWebLN.sendPayment(paymentRequest)`. If the wallet service pays successfully, the demo stores the returned preimage and renders it. If no preimage is present, the interface still says the invoice has not been paid.
This keeps the NWC story visible. The app is not building a shop, subscription system, tip jar or wallet dashboard. It proves that the provider can ask a wallet for balance and can send a Lightning payment through a BOLT-11 invoice.
The smallness also shows what production would still need. A real mobile app should not hard-code a demo Lightning address, assume one-satoshi invoices, treat a missing preimage as the only failure state or leave errors as console output. It should distinguish user cancellation, relay timeout, wallet rejection, insufficient balance, quota limits, unsupported methods and invoices that settle after the UI has already moved on.
Why mobile crypto is the hard part
The demo imports `./applyGlobalPolyfills` before it imports the SDK provider. That order is not cosmetic. It installs browser-like primitives that the SDK and its Nostr dependencies expect but the React Native runtime may not provide in the same way as a web browser.
`applyGlobalPolyfills.ts` imports `react-native-url-polyfill/auto`, `react-native-get-random-values`, `message-port-polyfill` and `text-encoding`. It then assigns `TextEncoder` and `TextDecoder` onto `global`. In plain language, the demo is making the mobile JavaScript environment look enough like a web environment for the SDK path to run.
The visible app also renders PolyfillCrypto from `react-native-webview-crypto`. That library's README says it brings `window.crypto.subtle` to React Native by communicating with a hidden WebView that performs the cryptographic computation. Its own instructions say rendering `PolyfillCrypto` starts the WebView that proxies the crypto calls.
This is the central caveat of the project. A NWC app signs and encrypts wallet authority messages. If your runtime lacks the expected cryptographic APIs, you need a shim. A shim may be correct enough for a demo while still demanding maintenance review, performance testing, platform testing and threat-model review before it guards real money.
The open issue points at the same risk
The repository has one open issue: `react-native-webview-crypto is not maintained`. The issue body says the dependency works, then asks whether there is a better-maintained or more standard library than `react-native-webview-crypto` that supports `crypto.subtle`.
That issue is not noise. It identifies the exact seam where a mobile NWC app can age badly. The app may compile, the WebView may render and the SDK may initialize, but the long-term safety of the cryptographic polyfill still matters.
The dependency itself is not dead by repository metadata alone. The `react-native-webview-crypto` GitHub repository was public and not archived when checked, and npm exposed a newer `0.0.28` release than the demo's `^0.0.25` range. But maintainership, API compatibility and React Native runtime compatibility are not answered by version numbers alone.
A serious app should test the crypto path on the exact Expo SDK, React Native version, JavaScript engine and platforms it intends to support. It should also track whether the Alby SDK or the broader React Native ecosystem offers a cleaner Web Crypto path before shipping payment authority through a WebView-backed shim.
How the Alby SDK fits
The demo uses the Alby JS SDK's WebLN-facing surface rather than the lower-level NWC client. The Alby guide describes two interfaces: `NWCClient`, which exposes NWC more directly and is recommended outside web contexts such as native mobile, command line and server backends; and `NostrWebLNProvider`, which exposes a WebLN-style API through NWC.
The demo chooses `NostrWebLNProvider`, which makes sense for a compact example because the calls are easy to recognize: `enable`, `getBalance` and `sendPayment`. That gives web developers a familiar WebLN mental model while still using Nostr Wallet Connect underneath.
The SDK source shows the mapping. `get_balance` becomes `getBalance`, `pay_invoice` becomes `sendPayment`, `make_invoice` becomes `makeInvoice`, and other NWC methods map into WebLN-like names such as lookup, transaction listing, keysend, multi-pay and message signing.
There is a tradeoff. `NostrWebLNProvider` is friendly when your UI already thinks in WebLN verbs. `NWCClient` may be a better foundation when you want direct control over NIP-47 methods, authorization metadata, request methods, encryption choices, notifications or wallet-service information. A production mobile app should make that choice deliberately rather than inheriting the demo's shortest path.
NIP-47 under the screen
Under the React Native screen, the protocol is still NIP-47 Nostr Wallet Connect. A client receives or creates a connection URI, uses relays from that URI and sends encrypted wallet requests to a wallet service public key.
NIP-47 defines request events as kind `23194`, response events as kind `23195` and wallet-service info events as kind `13194`. A `pay_invoice` request is encrypted in the event content and addressed to the wallet service with tags. The relay can route the event, but it should not read the payment payload.
The connection URI is the sensitive object. It uses a `nostr+walletconnect://` scheme, carries the wallet service public key, includes one or more `relay` parameters and includes a `secret` parameter that gives the app its signing and encryption authority. NIP-47 also recommends including a Lightning address when available.
That means the mobile UX has to respect the credential. A QR scan, paste field or authorization callback can all deliver the same level of wallet authority. The app should show the user what the connection can do, store it like a wallet secret and make revocation or replacement easy.
Encryption compatibility keeps moving
Current NIP-47 text says NWC content is encrypted with NIP-44 and also documents backwards compatibility with the earlier NIP-04 version. The spec describes an info-event `encryptions` tag and says clients should prefer `nip44_v2` when it is supported.
The Alby SDK source reflects that transition. Its NWC types include `nip04` and `nip44_v2`, and its client code parses wallet service information, reads encryption tags, defaults older services toward NIP-04 behavior and throws an unsupported-encryption error when no compatible path is available.
For the React Native demo, this is another reason to avoid treating the screen as the whole integration. Your production app needs to know what the SDK version can negotiate today, what the target wallet services advertise and whether your mobile runtime polyfills support the cryptographic operations required by the chosen encryption mode.
NIP-44 v2 is not just a label swap. It specifies secp256k1 ECDH, HKDF, ChaCha20, HMAC-SHA256, padding and authenticated payload handling. NIP-04, by contrast, is marked deprecated and unrecommended in the NIPs repository. The right mobile integration should be designed around current wallet-service behavior, not just around the first demo that compiles.
The dependency set has aged
`package.json` pins or ranges the demo around Expo `^52.0.14`, React Native `0.76.3`, React `18.3.1`, `@getalby/sdk` `^3.8.1`, `@getalby/lightning-tools` `^5.1.0`, `react-native-webview` `13.12.2` and `react-native-webview-crypto` `^0.0.25`.
Current npm metadata checked on June 15, 2026 showed newer versions for several of those packages, including `@getalby/sdk` `8.0.3`, `@getalby/lightning-tools` `8.1.1`, Expo `56.0.11`, React Native `0.86.0`, `react-native-webview` `13.16.1`, `react-native-get-random-values` `2.0.0` and `react-native-url-polyfill` `3.0.0`.
Version drift does not automatically mean the demo is broken. It means the demo captures a point in time. The latest commit was a dependency update in December 2024, while the SDK, Expo and React Native ecosystems continued moving afterward.
If you fork it today, update in layers. First make the current repository run unchanged. Then update Expo and React Native according to their migration paths. Then update the Alby packages and check whether the provider API, WebView authorization behavior, crypto polyfills and TypeScript types still line up. Finally, test on real iOS and Android devices, not only a desktop web target.
Expo configuration tells a shipping story
`app.json` names the app `NWC React native`, sets the slug to `nwc-react-native`, uses portrait orientation, points to icon and splash assets, sets bundle identifiers for iOS and Android and declares `ios.config.usesNonExemptEncryption` as false.
Expo's configuration docs explain that app config feeds Expo Prebuild, Expo Go loading and update manifests. The config schema notes that `usesNonExemptEncryption` maps into the iOS standalone app's `ITSAppUsesNonExemptEncryption` value.
That does not make the demo an app-store-ready wallet product. It does show that the repository was shaped as a real Expo project rather than a pasted snippet. It has EAS profiles, platform identifiers, TypeScript strictness and scripts for Android, iOS, web and EAS builds.
For a production NWC app, the config story gets broader. You need secure storage libraries, deep-link or universal-link return behavior if you avoid WebView-only authorization, privacy disclosures, network permissions, app icon ownership, test builds and a policy for how updates affect wallet credentials already stored on device.
What is missing for production
The demo keeps `nwcUrl`, `pendingNwcUrl`, `nwcAuthUrl`, provider state, balance, invoice and preimage in React component state. That is perfect for a sample. It is not a credential-management system. Closing the app, reloading the bundle or moving between screens is outside the demonstrated design.
There is no secure storage path. A shipped app needs to decide whether the NWC secret lives in Keychain, Keystore, encrypted storage or a server-side session. It also needs a way to delete the connection, rotate it and prevent debug logs or crash reports from carrying the URI.
There is no permission review screen. NIP-47 connections can be scoped by method, budget, expiration, maximum amount and related metadata depending on wallet support. A mobile app should show the user what it is asking for and what it will do with that authority.
There is no broad error model. The code logs caught errors to the console and renders simple text. NWC error codes include rate limits, unimplemented methods, insufficient balance, quota exceeded, internal errors, unsupported encryption and other failures. Those need user-visible states and developer-visible diagnostics.
There is no wallet compatibility matrix. A page can connect with Alby in a demo and still fail against another wallet service because of encryption, relay choice, authorization metadata, method support, budgets or notification behavior. A production app should test the wallets its users actually bring.
How to test the demo responsibly
Use a low-value NWC connection first. If you paste a URI, assume it can authorize whatever the wallet allowed when it was created. If you use the Alby flow, pay attention to the requested methods and budget. Do not test payment authority with a broad wallet connection you care about.
Run the paste path and authorization path separately. The paste path tells you whether the SDK provider can parse and use an existing NWC URI in the mobile runtime. The authorization path tells you whether the WebView handoff, injected message listener and `nwc:success` handling still work.
Test the read call before the pay call. `getBalance()` is a good liveness check, but it is not a full compatibility test. After that, use a tiny invoice you control, check whether `sendPayment` returns a preimage, and verify in the wallet service that the payment state matches what the app shows.
Run iOS and Android. React Native WebView behavior, safe areas, JavaScript engines, TLS, URL handling and crypto polyfills can differ by platform. A test that only passes in Expo's web mode does not prove the mobile NWC path.
Where it sits beside other NWC tools
React Native (Expo) belongs in the same developer shelf as Alby JS SDK, NWC HTTP API, nwcjs and Python3 NWC Library. It is not a competing wallet interface. It is a runtime-specific example for app builders.
Compared with the Alby JS SDK page, this repo is narrower and more practical. It shows how that SDK behaves in Expo, including the WebView and polyfill work the SDK guide can only describe at a higher level.
Compared with nwcjs or Python3 NWC Library, it hides more protocol detail and exposes more product surface. You do not see the kind `23194` event built by hand, but you do see the authorization button, mobile state and WebView callback that a user-facing app must handle.
Compared with Flutter Package, it is useful for a different mobile stack. Both point to the same NWC problem: wallet connections are portable at the protocol level, but each mobile runtime has its own answer for crypto, storage, navigation and permission UX.
That is the ecosystem role. The page should help a React Native builder decide whether to start from the Alby SDK provider, drop to `NWCClient`, compare another platform package or use a test tool such as NWC Tester (Advanced) before touching a mobile build.
Bottom line
React Native (Expo) is worth opening because it demonstrates the uncomfortable part of mobile NWC integration. The protocol promises wallet access through relays, but the app still needs WebView authorization, global polyfills, Web Crypto support, runtime-specific testing and a safe way to carry a secret-bearing connection.
The demo is strongest as a reading and prototype aid. It proves the path from Connect with Alby or pasted NWC URL to balance lookup and invoice payment. It makes the mobile bridge visible without burying the reader in a full product architecture.
Its limits are the point of the review. No releases, no tags, no license metadata, an open crypto-polyfill concern, older dependency ranges, in-memory connection state and minimal error handling all say the same thing: learn from it, then build your own production shell.
A good mobile NWC app should keep this repo nearby, but it should also design around current NIP-47 encryption, scoped wallet authority, secure storage, wallet compatibility, platform testing and clear user feedback. The demo opens the door. It does not carry the wallet risk for you.
Sources worth opening
Open the repository, README, `App.tsx`, polyfill file and package manifest first. Then compare the Alby SDK guide, NIP-47, NIP-44, NIP-04 and the React Native WebView crypto dependency before deciding what belongs in a production mobile app.
- React Native (Expo) GitHub repository
- React Native (Expo) raw README
- React Native (Expo) raw App.tsx
- React Native (Expo) raw package.json
- React Native (Expo) raw applyGlobalPolyfills.ts
- React Native (Expo) raw app.json
- React Native (Expo) raw eas.json
- React Native (Expo) raw tsconfig.json
- React Native (Expo) raw webln-types.d.ts
- React Native (Expo) repository metadata API
- React Native (Expo) contents API
- React Native (Expo) commits API
- React Native (Expo) open issue on WebView crypto
- awesome-nwc raw README
- NWC SDKs and Tools docs
- NWC app best practices docs
- NWC reference API overview
- NWC get_balance reference
- NWC pay_invoice reference
- NWC make_invoice reference
- Alby NWC JS SDK guide
- Alby JS SDK raw NWC docs
- Alby JS SDK GitHub repository API
- npm @getalby/sdk latest metadata
- Alby JS SDK NostrWebLNProvider source
- Alby JS SDK NWCClient source
- Alby JS SDK NWC types source
- NIP-47 raw specification
- NIP-44 raw specification
- NIP-04 raw specification
- NIP-01 raw specification
- React Native WebView Crypto GitHub repository
- React Native WebView Crypto raw README
- npm react-native-webview-crypto latest metadata
- npm expo latest metadata
- npm react-native latest metadata
- npm react-native-webview latest metadata
- Expo app configuration docs
- Expo app config schema
- Expo Hermes guide
- React Native Hermes docs





