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

spam-sdk

v1.2.0

Published

A simple Redux SDK for device ID management

Readme

Spam Detection SDK

A comprehensive React Native SDK for detecting and preventing spam behavior including API abuse, rapid screen switching, network manipulation, and emulator usage.

Features

🛡️ Multi-layered Spam Detection

  • API call rate limiting and abuse detection
  • Rapid screen switching detection
  • Network switching/manipulation detection
  • Emulator usage detection

⚙️ Intelligent Configuration

  • Server-based configuration with local fallbacks
  • Real-time config updates without app restart
  • Configurable thresholds and blocking behavior

🔄 Advanced State Management

  • Redux-based architecture with persistence
  • Automatic reset mechanisms (time-based)
  • Historical tracking with maxEver persistence

🚨 Smart Blocking System

  • Configurable blocking UI with custom messages
  • Automatic unblocking when limits are adjusted
  • Multiple blocking reasons with detailed descriptions

🧪 Comprehensive Testing

  • Built-in test utilities for all spam detection components
  • Debug logging and state inspection tools
  • Manual testing functions for development

Installation

npm install ../spam-sdk

Dependencies

Required peer dependencies:

  • react-native-device-info >= 10.0.0
  • @react-native-async-storage/async-storage
  • @react-native-netinfo/netinfo
  • @react-navigation/native (for screen tracking)

Quick Start

1. Redux Store Setup

// store/index.js
import { createStore, combineReducers } from 'redux';
import { persistStore, persistReducer } from 'redux-persist';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { spamReducer, spamPersistConfig } from 'spam-sdk';

const rootReducer = combineReducers({
  // your app reducers
  spam: spamReducer,
});

const persistConfig = {
  key: 'root',
  storage: AsyncStorage,
  blacklist: ['spam'] // spam has its own persistence
};

const persistedReducer = persistReducer(persistConfig, rootReducer);
export const store = createStore(persistedReducer);
export const persistor = persistStore(store);

2. App Integration

// App.js
import React, { useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { NavigationContainer } from '@react-navigation/native';
import { initSpamSDK, BlockingScreen, screenTracker } from 'spam-sdk';

const App = () => {
  const dispatch = useDispatch();
  const spamState = useSelector(state => state.spam);
  const [blockingState, setBlockingState] = useState({ isBlocked: false });

  useEffect(() => {
    initializeSpamSDK();
  }, []);

  const initializeSpamSDK = async () => {
    const onBlockingStateChange = (blockingData) => {
      setBlockingState(blockingData);
    };

    const result = await initSpamSDK(dispatch, {
      baseUrl: 'https://your-api.com',
      onBlockingStateChange,
      getState: () => store.getState().spam,
    });

    if (result.success) {
      console.log('✅ Spam SDK initialized');
    }
  };

  // Screen tracking integration
  const handleNavigationStateChange = (state) => {
    const getCurrentRoute = (state) => {
      if (!state?.routes?.length) return null;
      const route = state.routes[state.index];
      return route.state ? getCurrentRoute(route.state) : route.name;
    };
    
    const currentScreen = getCurrentRoute(state);
    if (currentScreen) {
      screenTracker.trackScreenChange(currentScreen);
    }
  };

  return (
    <View style={{ flex: 1 }}>
      <NavigationContainer onStateChange={handleNavigationStateChange}>
        {/* Your app navigation */}
      </NavigationContainer>
      
      {/* Spam Detection Blocking Screen */}
      <BlockingScreen 
        isBlocked={blockingState.isBlocked}
        reason={blockingState.reason}
        description={blockingState.description}
      />
    </View>
  );
};

Spam Detection Components

1. API Call Rate Limiting

Detects and blocks excessive API usage.

Configuration:

{
  apiCalls: {
    enabled: true,
    maxCountBeforeBlock: 100,    // Max API calls before blocking
    resetType: "per_min",        // Reset interval
    trackMaxHits: true           // Track historical maximum
  }
}

Behavior:

  • Tracks maxHitsEver (persists across app restarts)
  • Once exceeded, apiCallsSpam: true until config limit increases
  • Automatic blocking when limit exceeded

2. Screen Switching Detection

Prevents rapid navigation abuse and bot-like behavior.

Configuration:

{
  screenSwitching: {
    enabled: true,
    maxSwitches: 10,             // Max switches per minute
    timeWindowMinutes: 1,        // Time window for counting
    minTimeThreshold: 500,       // Rapid switching threshold (ms)
    blockSuspicious: true,       // Enable blocking
    trackHistory: true           // Track switch history
  }
}

Features:

  • Automatic screen change detection via React Navigation
  • Time-based reset every minute
  • Persistent maxSwitchesEver tracking
  • Blocks rapid navigation patterns

3. Network Switching Detection

Detects network manipulation and VPN switching.

Configuration:

{
  networkSwitching: {
    enabled: true,
    maxChanges: 3,               // Max network changes
    maxRapidChanges: 100,        // Max rapid changes
    timeWindowMinutes: 10,       // Time window
    blockSuspicious: true,       // Enable blocking
    trackHistory: true           // Track network history
  }
}

Detection:

  • Monitors network changes via NetInfo
  • Tracks unique networks and change patterns
  • Detects suspicious switching behavior

4. Emulator Detection

Identifies and optionally blocks emulator usage.

Configuration:

{
  emulator: {
    enabled: true,
    blockEmulator: false,        // Block emulator usage
    allowDevelopment: false,     // Allow in development
    showWarning: true            // Show warning messages
  }
}

Detection Methods:

  • Hardware characteristics analysis
  • OS-level emulator indicators
  • Development environment detection

Configuration System

Server Configuration

The SDK now accepts server configuration as an object instead of making API calls. This gives you full control over how you fetch the config from your server.

Basic Usage

import { initSpamSDK } from 'spam-sdk';

const initializeSDK = async () => {
  // Fetch config from your server however you want
  const serverConfig = await fetchConfigFromYourServer();
  
  // Initialize SDK with the config
  const result = await initSpamSDK(dispatch, {
    serverConfig,
    onBlockingStateChange: (blockingData) => {
      console.log('App blocked:', blockingData);
    },
  });
};

Server Config Format

Your server should return a config object with this structure:

const serverConfig = {
  "apiCalls": {
    "enabled": true,
    "maxCountBeforeBlock": 100,
    "resetType": "per_min",
    "trackMaxHits": true
  },
  "blocking": {
    "enabled": false,
    "showReason": false,
    "customMessage": null
  },
  "emulator": {
    "enabled": true,
    "blockEmulator": false,
    "showWarning": true,
    "allowDevelopment": false
  },
  // ... other config sections
};

Supported Config Formats

The SDK automatically handles different response formats:

  1. Direct config object:
const serverConfig = { apiCalls: {...}, blocking: {...} };
  1. API response wrapper:
const serverConfig = {
  "success": true,
  "data": { apiCalls: {...}, blocking: {...} }
};
  1. Config wrapper:
const serverConfig = {
  "config": { apiCalls: {...}, blocking: {...} }
};

Example Implementation

const fetchConfigFromYourServer = async () => {
  try {
    const response = await fetch('https://your-api.com/spam-config', {
      method: 'GET',
      headers: {
        'Authorization': 'Bearer your-token',
        'version': '90',
      },
    });

    if (!response.ok) {
      throw new Error(`HTTP ${response.status}`);
    }

    return await response.json();
  } catch (error) {
    console.error('Failed to fetch config:', error);
    return null; // SDK will use defaults
  }
};

Local Configuration

Fallback configuration when server is unavailable:

// spam-sdk/src/config/spamConfig.js
export const DEFAULT_SPAM_CONFIG = {
  apiCalls: {
    enabled: true,
    maxCountBeforeBlock: 100,
    resetType: "per_min",
    trackMaxHits: true
  },
  screenSwitching: {
    enabled: true,
    maxSwitches: 10,
    timeWindowMinutes: 1,
    minTimeThreshold: 500,
    blockSuspicious: true,
    trackHistory: true
  },
  // ... other components
};

State Structure

{
  // Core SDK state
  isInitialized: false,
  deviceIds: {
    appInstanceId: "uuid-v4",
    osDeviceId: "android-id-or-idfv", 
    hardwareId: "hardware-fingerprint"
  },
  deviceInfo: {
    model: "iPhone 14",
    brand: "Apple",
    systemName: "iOS",
    systemVersion: "16.0"
  },
  isEmulator: false,
  
  // Spam detection state
  spamScore: {
    apiCallsSpam: false,
    emulatorSpam: false,
    networkSpam: false,
    screenSpam: false,
    overallScore: 0.0,
    lastUpdated: 1640995200000
  },
  
  // API call tracking
  apiCallsCount: {
    total: 45,
    maxHitsEver: 87,              // Persists across resets
    lastReset: 1640995200000,
    resetType: "per_min"
  },
  
  // Screen switching tracking
  screenSwitching: {
    currentScreen: "Home",
    previousScreen: "Profile",
    switchCount: 3,
    maxSwitchesEver: 15,          // Persists across resets
    uniqueScreensCount: 8,
    sessionScreenHistory: ["Home", "Profile", "Settings"],
    switchHistory: [/* switch records */],
    isTracking: true
  },
  
  // Network tracking
  networkTracking: {
    currentNetworkId: "wifi_home",
    changeCount: 1,
    uniqueNetworkCount: 3,
    sessionNetworkIds: ["wifi_home", "4g_cellular"],
    networkChangeHistory: [/* change records */],
    isTracking: true
  },
  
  // Configuration
  spamConfig: {
    // Server configuration merged with defaults
  },
  
  // Blocking state
  blockedStatus: {
    isBlocked: false,
    reason: null,                 // 'api_calls', 'screen_switching', etc.
    description: null,
    timestamp: null
  }
}

API Reference

Initialization

initSpamSDK(dispatch, options)

State Selectors

getSpamScore(state)           // Get spam detection scores
getApiCallsCount(state)       // Get API call statistics
getScreenSwitching(state)     // Get screen switching data
getNetworkTracking(state)     // Get network tracking data
getBlockedStatus(state)       // Get blocking status
isSDKInitialized(state)       // Check initialization

Actions

setSpamScore(data)           // Update spam scores
setApiCallsCount(data)       // Update API call count
updateScreenSwitching(data)  // Update screen switching
updateNetworkState(data)     // Update network state
setBlockedStatus(data)       // Set blocking status
setSpamConfig(config)        // Update configuration

Utilities

performSpamCheck(state)      // Manual spam check
resetScreenSession()         // Reset screen tracking
resetNetworkSession()        // Reset network tracking

Testing & Debugging

Built-in Test Functions

import { 
  testApiCalls, 
  testScreenSwitching, 
  testNetworkSwitching,
  forceUnblockApp 
} from 'spam-sdk';

// Test API call detection
testApiCalls(dispatch, 50);

// Test screen switching
testScreenSwitching(dispatch, 15);

// Test network switching  
testNetworkSwitching(dispatch, 5);

// Emergency unblock
forceUnblockApp(dispatch);

Debug Logging

Enable detailed logging:

// All spam detection actions log detailed information
console.log('[SpamSDK] 🚨 API calls spam detected: 105/100');
console.log('[SpamSDK] 📱 Screen switch: Home → Profile (3/10)');
console.log('[SpamSDK] 🌐 Network change: wifi → cellular (2/3)');

State Inspection

// Check current spam detection status
const spamState = useSelector(state => state.spam);
console.log('API Calls Spam:', spamState.spamScore.apiCallsSpam);
console.log('Screen Spam:', spamState.spamScore.screenSpam);
console.log('Is Blocked:', spamState.blockedStatus.isBlocked);

Blocking System

Custom Blocking UI

import { BlockingScreen } from 'spam-sdk';

<BlockingScreen 
  isBlocked={blockingState.isBlocked}
  reason={blockingState.reason}
  description={blockingState.description}
  showReason={false}           // Show/hide technical details
  customMessage="Access temporarily restricted"
/>

Blocking Reasons

  • api_calls - Excessive API usage
  • screen_switching - Rapid screen navigation
  • network_switching - Network manipulation
  • emulator - Emulator usage detected

Automatic Unblocking

The SDK automatically unblocks users when:

  • Configuration limits are increased
  • Blocking is disabled in config
  • Manual unblock functions are called

Advanced Usage

Custom Configuration

// Override default configuration
const customConfig = {
  apiCalls: { maxCountBeforeBlock: 200 },
  screenSwitching: { maxSwitches: 20 },
  blocking: { enabled: false }
};

spamConfigManager.updateConfig(customConfig);

Manual Spam Detection

// Trigger manual spam check
const currentState = store.getState().spam;
const result = performSpamCheck(currentState);
console.log('Spam detected:', result.isSpam);

Integration with Analytics

// Track spam events
useEffect(() => {
  if (spamState.spamScore.apiCallsSpam) {
    analytics.track('spam_detected', { type: 'api_calls' });
  }
}, [spamState.spamScore]);

Best Practices

1. Configuration Management

  • Use server-based configuration for production
  • Test configuration changes in development
  • Monitor spam detection metrics

2. User Experience

  • Provide clear blocking messages
  • Implement appeal/contact mechanisms
  • Use graduated responses (warnings before blocks)

3. Development

  • Use test functions during development
  • Monitor console logs for debugging
  • Test edge cases and false positives

4. Performance

  • SDK is optimized for minimal performance impact
  • Uses efficient Redux state management
  • Automatic cleanup and memory management

Troubleshooting

Common Issues

SDK not initializing:

// Check Redux store setup
console.log('Store state:', store.getState());

// Verify dependencies
import DeviceInfo from 'react-native-device-info';

Screen tracking not working:

// Ensure navigation state listener is set up
<NavigationContainer onStateChange={handleNavigationStateChange}>

False positives:

// Adjust configuration thresholds
const config = { screenSwitching: { maxSwitches: 20 } };

Emergency unblock:

import { forceUnblockApp } from 'spam-sdk';
forceUnblockApp(dispatch);

License

MIT License - see LICENSE file for details.

Support

For issues and questions:

  1. Check the troubleshooting section
  2. Review console logs for detailed error information
  3. Use built-in test functions to isolate issues
  4. Contact development team with specific error details