ping-identity
    Preparing search index...

    Ping Identity

    Ping Identity React Native Protect

    The Ping Protect library integrates PingOne Protect behavioral data collection into your React Native application. Acting as a plugin for the davinci module, it runs silent background risk signals collection during a DaVinci flow so that your backend can make an informed authentication decision.

    When a DaVinci flow includes a PROTECT collector, the native PingOne Protect SDK collects behavioral and device signals in the background. This library bridges that native collection to your React Native app — call daVinci.collectProtect() before advancing the flow, and the collected payload is forwarded automatically on the next daVinci.next({}) call.

    No foreground window, activity, or user interaction is required. Collection runs entirely in the background.

    Note: This module requires that @ping-identity/rn-core and @ping-identity/rn-davinci are already installed.

    yarn add @ping-identity/rn-protect
    # iOS only
    cd ios && pod install

    Optional integration:

    yarn add @ping-identity/rn-logger
    

    Pass modules.protect to createDaVinciClient to wire the Protect SDK into the DaVinci workflow lifecycle automatically. The native SDK initializes on workflow start, resumes behavioral data collection at the beginning of each node, and pauses it on success — without any manual startProtect() call.

    import { createDaVinciClient } from '@ping-identity/rn-davinci';
    import { logger } from '@ping-identity/rn-logger';

    const client = createDaVinciClient({
    logger: logger({ level: 'debug' }),
    modules: {
    oidc: {
    clientId: 'rn-client',
    discoveryEndpoint:
    'https://auth.pingone.com/<env-id>/as/.well-known/openid-configuration',
    redirectUri: 'com.example.app://callback',
    scopes: ['openid'],
    },
    protect: {
    envId: 'your-pingone-environment-id',
    isBehavioralDataCollection: true,
    pauseBehavioralDataOnSuccess: true,
    resumeBehavioralDataOnStart: true,
    logger: logger({ level: 'debug' }), // optional — scoped to Protect operations
    },
    },
    });

    All protect fields are optional. If @ping-identity/rn-protect is not installed, the modules.protect value is silently ignored at runtime.

    When the lifecycle module is active, use daVinci.collectProtect() directly on the DaVinci client before advancing the flow:

    await daVinci.collectProtect();
    await daVinci.next({});

    Use this path when you need direct control over initialization timing, or when using Protect outside a DaVinci flow.

    import { startProtect } from '@ping-identity/rn-protect';

    await startProtect({
    envId: 'your-pingone-environment-id',
    isBehavioralDataCollection: true,
    resumeBehavioralDataOnStart: true,
    });

    With optional logger:

    import { startProtect } from '@ping-identity/rn-protect';
    import { logger } from '@ping-identity/rn-logger';

    const protectLogger = logger({ level: 'debug' });

    await startProtect({
    envId: 'your-pingone-environment-id',
    logger: protectLogger,
    });

    When modules.protect is configured on createDaVinciClient, call daVinci.collectProtect() directly — no separate protect object needed:

    try {
    await daVinci.collectProtect();
    const node = await daVinci.next({});
    } catch (error) {
    // See Errors section
    }

    Control behavioral data collection manually to mirror the ProtectLifecycleModule behavior from the native SDK. Call pauseBehavioralData() after a successful flow and resumeBehavioralData() when a new flow starts.

    import {
    pauseBehavioralData,
    resumeBehavioralData,
    } from '@ping-identity/rn-protect';

    // After a successful authentication flow:
    await pauseBehavioralData();

    // At the start of a new authentication flow:
    await resumeBehavioralData();

    With an optional logger:

    await pauseBehavioralData({ logger: protectLogger });
    await resumeBehavioralData({ logger: protectLogger });

    If you set resumeBehavioralDataOnStart: true in startProtect, it calls resumeBehavioralData() automatically after initialization.

    Pass handledCollectorTypes so PROTECT collectors are excluded from blocking submit issues. Without this, buildNextInput returns canSubmit: false when a PROTECT collector is present.

    import { useDaVinci, useDaVinciForm } from '@ping-identity/rn-davinci';

    const { node, next } = useDaVinci(daVinciClient);
    const form = useDaVinciForm(node, {
    handledCollectorTypes: new Set(['PROTECT']),
    });

    // Before submitting the form, run collection:
    await daVinciClient.collectProtect();

    if (form.canSubmit) {
    await next(form.input);
    }
    import React, { useEffect } from 'react';
    import {
    useDaVinci,
    useDaVinciForm,
    createDaVinciClient,
    } from '@ping-identity/rn-davinci';

    const daVinciClient = createDaVinciClient({
    modules: {
    oidc: {
    /* ... */
    },
    protect: {
    envId: 'your-pingone-environment-id',
    resumeBehavioralDataOnStart: true,
    },
    },
    });

    function LoginScreen() {
    const { node, next } = useDaVinci(daVinciClient);
    const form = useDaVinciForm(node, {
    handledCollectorTypes: new Set(['PROTECT']),
    });

    useEffect(() => {
    if (node?.type !== 'ContinueNode') return;
    const hasProtect = node.collectors.some((c) => c.type === 'PROTECT');
    if (!hasProtect) return;

    daVinciClient.collectProtect().catch(console.error);
    }, [node]);

    async function handleSubmit() {
    if (!form.canSubmit) return;
    await next(form.input);
    }

    // ... render form fields
    }

    import {
    startProtect,
    pauseBehavioralData,
    resumeBehavioralData,
    } from '@ping-identity/rn-protect';
    import type {
    ProtectConfig,
    ProtectErrorCode,
    } from '@ping-identity/rn-protect';

    function startProtect(config?: ProtectConfig): Promise<void>;
    function pauseBehavioralData(options?: {
    logger?: LoggerInstance;
    }): Promise<void>;
    function resumeBehavioralData(options?: {
    logger?: LoggerInstance;
    }): Promise<void>;

    interface ProtectConfig {
    /** Optional logger instance from @ping-identity/rn-logger. */
    logger?: LoggerInstance;
    /** PingOne environment ID for the Protect SDK. */
    envId?: string;
    /** Whether to enable behavioral data collection. Default: true. */
    isBehavioralDataCollection?: boolean;
    /** Whether to use lazy metadata loading. Default: false. */
    isLazyMetadata?: boolean;
    /** Custom host URL for the Protect SDK. */
    customHost?: string;
    /** Whether to enable console logging inside the Protect SDK. Default: false. */
    isConsoleLogEnabled?: boolean;
    /** Device attributes to exclude from signal collection. */
    deviceAttributesToIgnore?: string[];
    /** When true, startProtect() resumes behavioral data collection automatically. Default: false. */
    resumeBehavioralDataOnStart?: boolean;
    /** Documents intent to pause after success — call pauseBehavioralData() manually. Default: false. */
    pauseBehavioralDataOnSuccess?: boolean;
    }

    All promise rejections throw a ProtectError instance, which extends PingError extends Error. Use instanceof to narrow the error type:

    import { ProtectError } from '@ping-identity/rn-protect';

    try {
    await daVinci.collectProtect();
    } catch (err) {
    if (err instanceof ProtectError) {
    console.log(err.code, err.message);
    }
    }

    Stable error codes:

    • PROTECT_INITIALIZE_ERROR — the native Protect SDK failed to initialize, pause, or resume.
    • PROTECT_COLLECT_ERROR — the native Protect SDK failed to collect signals.
    • PROTECT_COLLECTOR_NOT_FOUND — no PROTECT collector was found at the specified index.

    This project is licensed under the MIT License - see the LICENSE file for details.