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

@silicon.js/device-id

v1.0.9

Published

A robust React Native package for generating, storing, and managing unique device identifiers. This package provides persistent device IDs across app sessions with fallback support and a context-based API.

Readme

React Native Device ID Package

A robust React Native package for generating, storing, and managing unique device identifiers. This package provides persistent device IDs across app sessions with fallback support and a context-based API.

Features

  • 🔑 Platform-native IDs: Uses iOS Vendor ID and Android ID when available
  • 💾 Persistent Storage: Stores device ID in AsyncStorage for consistency
  • 🔄 Automatic Fallback: Generates UUID v4 if native IDs are unavailable
  • 🎯 Context-based API: Easy access throughout your component tree
  • 🎣 Flexible Hooks: Use with or without context
  • Async Support: Built with async/await for optimal performance
  • 🛡️ Error Handling: Comprehensive error catching and callbacks
  • 🔧 Device Management: Delete and regenerate IDs as needed

Installation

npm install expo-application @react-native-async-storage/async-storage uuid

or

yarn add expo-application @react-native-async-storage/async-storage uuid

Install Types (TypeScript)

npm install --save-dev @types/uuid

Setup

1. Configure Storage Key

Create a constants file or add to your existing constants:

// constants.ts or constants/index.ts
export const DEVICE_ID_STORAGE_KEY = '@app:deviceId';

2. Wrap Your App with DeviceIdProvider

import { DeviceIdProvider } from './path-to-package';

function App() {
  const handleSuccess = (deviceId: string) => {
    console.log('Device ID loaded:', deviceId);
    // Send to analytics, backend, etc.
  };

  const handleError = (error: Error) => {
    console.error('Device ID error:', error);
  };

  return (
    <DeviceIdProvider onSuccess={handleSuccess} onError={handleError} enabled={true}>
      <YourApp />
    </DeviceIdProvider>
  );
}

Usage

Using the Context Hook (Recommended)

Access device ID anywhere in your component tree:

import { useDeviceIdContext } from './path-to-package';

function MyComponent() {
  const { deviceId, isLoading, error, getDeviceId, deleteDeviceId, regenerateDeviceId } =
    useDeviceIdContext();

  if (isLoading) {
    return <Text>Loading device ID...</Text>;
  }

  if (error) {
    return <Text>Error: {error.message}</Text>;
  }

  return (
    <View>
      <Text>Device ID: {deviceId}</Text>
      <Button title="Refresh ID" onPress={getDeviceId} />
      <Button title="Regenerate ID" onPress={regenerateDeviceId} />
      <Button title="Delete ID" onPress={deleteDeviceId} />
    </View>
  );
}

Using the Hook Directly

Use without context for more control:

import { useDeviceId } from './path-to-package';

function StandaloneComponent() {
  const { deviceId, isLoading, error, regenerateDeviceId } = useDeviceId({
    enabled: true,
    onSuccess: (id) => {
      console.log('Got device ID:', id);
    },
    onError: (err) => {
      console.error('Failed to get device ID:', err);
    },
  });

  return (
    <View>
      {isLoading ? (
        <ActivityIndicator />
      ) : (
        <>
          <Text>ID: {deviceId}</Text>
          <Button title="New ID" onPress={regenerateDeviceId} />
        </>
      )}
    </View>
  );
}

Manual Device ID Generation

Use the utility function directly:

import { deviceIdUtils } from './path-to-package';

async function generateNewId() {
  const deviceId = await deviceIdUtils.generate();
  console.log('New device ID:', deviceId);
  return deviceId;
}

API Reference

DeviceIdProvider

Provider component that manages device ID state and makes it available via context.

Props:

  • onSuccess?: (deviceId: string) => void | Promise<void> - Optional callback when device ID is successfully loaded/generated
  • onError?: (error: Error) => void - Optional callback when an error occurs
  • enabled?: boolean - Whether to automatically load device ID on mount (default: true)
  • methods?: UseDeviceIdResult - Optional custom methods to override default behavior
  • children: React.ReactNode - Child components

useDeviceIdContext()

Hook to access device ID context. Must be used within a DeviceIdProvider.

Returns:

{
  deviceId: string | null;
  isLoading: boolean;
  error: Error | null;
  getDeviceId: () => Promise<string | null>;
  deleteDeviceId: () => Promise<void>;
  regenerateDeviceId: () => Promise<void>;
}

Throws: Error if used outside of DeviceIdProvider

useDeviceId(options?)

Hook for managing device ID independently (works without provider).

Parameters:

{
  onSuccess?: (deviceId: string) => void | Promise<void>;
  onError?: (error: Error) => void;
  enabled?: boolean; // default: true
}

Returns:

{
  deviceId: string | null;
  isLoading: boolean;
  error: Error | null;
  getDeviceId: () => Promise<string | null>;
  deleteDeviceId: () => Promise<void>;
  regenerateDeviceId: () => Promise<void>;
}

deviceIdUtils.generate()

Utility function to generate a new device ID.

Returns: Promise<string>

Behavior:

  • iOS: Returns Application.getIosIdForVendorAsync() result
  • Android: Returns Application.getAndroidId() result
  • Fallback: Returns UUID v4 if native methods fail

Methods

getDeviceId()

Retrieves the current device ID from storage.

const id = await getDeviceId();
console.log('Current device ID:', id);

deleteDeviceId()

Removes the device ID from storage and clears the state.

await deleteDeviceId();
console.log('Device ID deleted');

regenerateDeviceId()

Generates a new device ID and replaces the existing one.

await regenerateDeviceId();
console.log('Device ID regenerated');

Device ID Behavior

Generation Strategy

  1. iOS: Uses Application.getIosIdForVendorAsync()

    • Unique per vendor (developer)
    • Persists across app reinstalls if another app from same vendor is installed
    • Changes if all apps from vendor are uninstalled
  2. Android: Uses Application.getAndroidId()

    • Unique per app installation
    • Changes on factory reset or app reinstall
  3. Fallback: Generates UUID v4

    • Used if native methods fail
    • Cryptographically random

Storage

  • Device IDs are stored in AsyncStorage using the key defined in DEVICE_ID_STORAGE_KEY
  • IDs persist across app sessions
  • IDs are automatically loaded on app startup (if enabled: true)

Lifecycle

  1. On first app launch: Generate and store new ID
  2. On subsequent launches: Load existing ID from storage
  3. If storage fails: Generate new ID but continue with in-memory value
  4. Manual operations: Delete or regenerate as needed

Complete Example

import React, { useEffect } from 'react';
import { View, Text, Button, ActivityIndicator, StyleSheet } from 'react-native';
import { DeviceIdProvider, useDeviceIdContext } from './path-to-package';

function DeviceInfo() {
  const { deviceId, isLoading, error, getDeviceId, deleteDeviceId, regenerateDeviceId } =
    useDeviceIdContext();

  useEffect(() => {
    if (deviceId) {
      // Send to analytics or backend
      console.log('Device registered:', deviceId);
    }
  }, [deviceId]);

  if (isLoading) {
    return (
      <View style={styles.container}>
        <ActivityIndicator size="large" />
        <Text>Loading device ID...</Text>
      </View>
    );
  }

  if (error) {
    return (
      <View style={styles.container}>
        <Text style={styles.error}>Error: {error.message}</Text>
        <Button title="Retry" onPress={getDeviceId} />
      </View>
    );
  }

  return (
    <View style={styles.container}>
      <Text style={styles.title}>Device Information</Text>

      <View style={styles.idContainer}>
        <Text style={styles.label}>Device ID:</Text>
        <Text style={styles.id}>{deviceId}</Text>
      </View>

      <View style={styles.actions}>
        <Button title="Refresh" onPress={getDeviceId} />
        <Button title="Regenerate" onPress={regenerateDeviceId} color="#ff9500" />
        <Button title="Delete" onPress={deleteDeviceId} color="#ff3b30" />
      </View>
    </View>
  );
}

export default function App() {
  const handleSuccess = async (deviceId: string) => {
    console.log('Device ID ready:', deviceId);

    // Example: Send to backend
    // await api.registerDevice(deviceId);
  };

  const handleError = (error: Error) => {
    console.error('Device ID error:', error);
    // Example: Log to error tracking service
    // Sentry.captureException(error);
  };

  return (
    <DeviceIdProvider onSuccess={handleSuccess} onError={handleError} enabled={true}>
      <DeviceInfo />
    </DeviceIdProvider>
  );
}

Use Cases

  • User Analytics: Track unique users without authentication
  • Device Fingerprinting: Identify devices for security purposes
  • Session Management: Maintain sessions across app restarts
  • A/B Testing: Consistently assign users to test groups
  • Rate Limiting: Limit API requests per device
  • Fraud Detection: Identify suspicious device patterns

Error Handling

The package handles errors gracefully:

const { deviceId, error } = useDeviceIdContext();

if (error) {
  // Handle different error scenarios
  if (error.message.includes('storage')) {
    // Storage access issue
    console.log('Storage error, using temporary ID');
  } else if (error.message.includes('generate')) {
    // Generation failure
    console.log('Failed to generate ID');
  }
}

Platform Considerations

iOS

  • Vendor ID may change if user uninstalls all apps from the same vendor
  • Requires expo-application permissions

Android

  • Android ID changes on factory reset
  • Different behavior on Android 8.0+ (scoped per app signing key)

Web (Not Supported)

  • This package is designed for iOS and Android only
  • Web fallback would use UUID v4

Best Practices

  1. Initialize Early: Wrap your root component with DeviceIdProvider
  2. Handle Errors: Always provide onError callback for production apps
  3. Privacy: Inform users about device tracking in your privacy policy
  4. Don't Rely Solely: Use alongside other authentication methods
  5. Secure Storage: Consider encrypting sensitive device data
  6. GDPR Compliance: Provide way for users to delete their device ID

Dependencies

  • expo-application: For native device IDs
  • @react-native-async-storage/async-storage: For persistent storage
  • uuid: For fallback UUID generation
  • react: Peer dependency
  • react-native: Peer dependency

Troubleshooting

Device ID keeps changing

  • Check if AsyncStorage is working correctly
  • Verify DEVICE_ID_STORAGE_KEY is consistent
  • Ensure app isn't being uninstalled between tests

"Must be used within DeviceIdProvider" error

  • Make sure useDeviceIdContext() is called inside a component wrapped by DeviceIdProvider
  • Check that provider is in a parent component

Storage errors

  • Verify @react-native-async-storage/async-storage is properly installed
  • Check storage permissions on device
  • Clear app data and retry