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-altcha

v2.0.0

Published

ALTCHA React Native widget supporting PoW v2

Readme

react-native-altcha

React Native widget for ALTCHA — supports PoW v2 with SHA, PBKDF2, Argon2id, and Scrypt algorithms, Human Interaction Signature (HIS) collection, and server-side verification.

Requirements

Benchmarks

Because of sub-optimal PBKDF2 performance in react-native-quick-crypto on iOS, we recommend using Argon2id if your project targets both platforms.

| Platform | 1 Worker | 4 Workers | | :--- | :--- | :--- | | Android (PBKDF2) | 7.2s (~0.4x) | 1.8s (~1.4x) | | Android (Argon2id) | 5.0s (~1.6x) | 1.7s (~2.0x) | | iOS (PBKDF2) | 6.3s (~0.5x) | 2.5s (~0.5x) | | iOS (Argon2id) | 2.3s (~2.2x) | 0.9s (~2.4x) |

Measurements were taken using PBKDF2/SHA-256 (cost=5000, counter=5000) and Argon2id (cost=2, memoryCost=32768, counter=100). Multipliers represent performance relative to the WebCrypto baseline on the same device.

All algorithms use crypto.subtle or the Node.js-style crypto module exposed by react-native-quick-crypto. On web, SHA-* and PBKDF2/* use the browser's native crypto.subtle.

Installation

npm install react-native-altcha
expo install expo-audio expo-localization react-native-svg
expo install react-native-quick-crypto react-native-nitro-modules react-native-quick-base64
expo prebuild

Crypto setup

Call install() in your app entry point before anything else renders. This polyfills global.crypto with a native C++ implementation (OpenSSL on Android, CommonCrypto on iOS):

// index.js
import { Platform } from 'react-native';

if (Platform.OS !== 'web') {
  require('react-native-quick-crypto').install();
}

import { registerRootComponent } from 'expo';
import App from './src/App';

registerRootComponent(App);

On web, crypto.subtle is available natively in the browser — no setup required.

Basic usage

import { useRef } from 'react';
import { AltchaWidget } from 'react-native-altcha';
import type { AltchaWidgetRef } from 'react-native-altcha';

export default function App() {
  const ref = useRef<AltchaWidgetRef>(null);

  return (
    <AltchaWidget
      ref={ref}
      challenge="..."
      onVerified={(payload) => {
        // Send payload to your backend
        console.log('Verified:', payload);
      }}
    />
  );
}

Human Interaction Signature (HIS)

Some ALTCHA configurations require HIS data — touch patterns, scroll, keyboard focus — to distinguish humans from bots. The server signals this by responding to the challenge request with { his: { url: "..." } } instead of a challenge.

For best coverage, attach the HIS collector at the app root so all touches are captured globally:

import { useMemo } from 'react';
import { View } from 'react-native';
import { HisCollector } from 'react-native-altcha';

export default function App() {
  const hisProps = useMemo(() => HisCollector.attach(), []);

  return (
    // Spread on the outermost View — captures all touches in the subtree
    <View style={{ flex: 1 }} {...hisProps}>
      {/* your app */}
    </View>
  );
}

To also capture scroll events, pass getScrollHandler() to your ScrollView:

<ScrollView
  onScroll={HisCollector.shared.getScrollHandler()}
  scrollEventThrottle={50}
>

Props

AltchaWidget

| Prop | Type | Default | Description | | ---------------------- | --------------------------------------------------------------- | -------------- | ------------------------------------------------------------------------------ | | challenge | string \| Challenge | — | URL to fetch the challenge from, or a pre-fetched Challenge object | | origin | string | — | App identifier sent as Origin/Referer headers (e.g. "com.example.myapp") | | onVerified | (payload: string) => void | required | Called with base64-encoded payload on success | | onFailed | (error: string) => void | — | Called if verification fails | | onServerVerification | (data: ServerSignatureVerificationData) => void | — | Called after successful server verification | | colorScheme | 'light' \| 'dark' | system | Override color scheme | | themes | { light?: Partial<AltchaTheme>, dark?: Partial<AltchaTheme> } | — | Theme overrides | | style | ViewStyle & { color?, fontSize? } | — | Widget container style | | hideLogo | boolean | false | Hide the ALTCHA logo | | hideFooter | boolean | false | Hide the "Protected by ALTCHA" footer | | locale | string | system locale | Language code ('en', 'de', 'es', 'fr', 'it', 'pt') | | customTranslations | Record<string, Partial<Translation>> | — | Override UI strings per locale | | workers | number | 1 | Concurrent solver chains — values > 1 parallelise across CPU cores | | minDuration | number | — | Minimum solving time (ms) — pads short solves to avoid instant UI flicker | | debug | boolean | false | Log requests and HIS data to console | | fetch | typeof fetch | global fetch | Custom fetch implementation | | httpHeaders | Record<string, string> | — | Extra HTTP headers added to all requests |

AltchaWidget ref methods

ref.current?.reset(); // Reset widget to unverified state
ref.current?.verify(); // Manually trigger verification

Theming

import { AltchaWidget, defaultThemes } from 'react-native-altcha';

<AltchaWidget
  themes={{
    light: {
      ...defaultThemes.light,
      primaryColor: '#6200ea',
      primaryContentColor: '#ffffff',
    },
    dark: {
      ...defaultThemes.dark,
      primaryColor: '#bb86fc',
    },
  }}
  challenge="..."
  onVerified={...}
/>

AltchaTheme fields

| Field | Default (light) | Default (dark) | | --------------------- | --------------- | -------------- | | backgroundColor | #ffffff | #1a1a1a | | borderColor | #cccccc | #444444 | | primaryColor | #007AFF | #007AFF | | primaryContentColor | #ffffff | #ffffff | | textColor | #000000 | #ffffff | | errorColor | #ff0000 | #ff0000 |

Internationalization

Built-in languages: English, German, Spanish, French, Italian, Portuguese.

Override individual strings:

<AltchaWidget
  customTranslations={{
    en: { label: 'Prove you are human' },
  }}
  challenge="..."
  onVerified={...}
/>

Advanced: direct solver API

import {
  solveChallenge,
  solveChallengeWorkers,
  hasSubtleCrypto,
  hasArgon2Support,
  hasScryptSupport,
} from 'react-native-altcha';

// Single-threaded
const solution = await solveChallenge(challenge);

// Multi-threaded (N concurrent chains)
const solution = await solveChallengeWorkers(challenge, 4);

Advanced: HIS collector static API

// Attach the global singleton and get root View props
const hisProps = HisCollector.attach(options?);  // { maxSamples?, sampleInterval? }

// Stop collection
HisCollector.detach();

// Access the shared instance
HisCollector.shared.export();  // { focus, pointer, scroll, touch, maxTouchPoints, time }
HisCollector.shared.getScrollHandler();  // onScroll handler for ScrollView

License

MIT