Using the Coinme Risk SDK for Web

Introduction

The Coinme Risk Engine SDK is a library, distributed as an NPM package, that allows you to interact with the Coinme Risk Engine from your application. It provides utilities that allow you to integrate against the Coinme risk engine for the various transactional flows in your application so that Coinme may appropriately assess transactional risk when processing transactions.

ℹ️

Note:

In order to utilize Coinme transactional services from within your application, you must implement and use the Coinme risk engine SDK.

What is it?

The Coinme risk engine aggregates data about user behavior for your application. It collects:

  • Device data such as the type of device, browser, etc.
  • Location data such as where the user is connecting from.
  • Connection data such as if the user is using a proxy or VPN, etc.
  • Behavioral data such as how a user is interacting with your application, how quickly they are entering data into fields, etc.

This data is used to determine the relative riskiness of the user / transaction.

⚠️

Why is Risk Tagging Important?

Risk tagging allows the SDK to track user interactions tied to specific actions within your application. When an element is tagged, the risk engine can better assess whether a user is behaving normally or if suspicious automation patterns are detected.

As an example, if the risk engine determines that the user is connected with an unknown browser type, via a VPN or proxy, and that interactions with elements of your app are happening much faster than would be normal for a human, then the engine may determine automation is at play and may rank the transaction as high risk.

How to Use the SDK

The Coinme Risk Engine SDK is an NPM package. You may install it as follows.

⚠️

This package is not public

You will need an auth token in order to install it. You may obtain this by working with the Coinme business development team.

What You'll Need to Get Started

Before integrating the SDK, you will need the following credentials from the Coinme business development team:

CredentialRequired ForNotes
NPM auth tokenInstalling the packageRequired to access the private npm registry
clientIdsetupCoinmeRiskEngineEnvironment-specific — you will need one for development and one for production
x-partner-idgetSessionTagPassed via additionalHeaders
x-ramp-idgetSessionTag (Ramp partners only)Passed via additionalHeaders

Installation

For SDK Consumers

To install the package, configure your .npmrc or .yarnrc (or equivalent) to include your authentication token:

@coinme-security:registry=https://npm.coinme.com/coinme-security-wrapper/
//npm.coinme.com/coinme-security-wrapper/:_authToken=<AUTHENTICATION_TOKEN>
always-auth=true
ℹ️

Note:

Replace <AUTHENTICATION_TOKEN> with your provided token.

Then install via:

NPM:

npm install @coinme-security/risk-sdk-js

Yarn:

yarn add @coinme-security/risk-sdk-js

PNPM:

pnpm add @coinme-security/risk-sdk-js

Quick Start

You can use the Coinme Risk Engine SDK in your project by following the steps below.

Setup the Coinme Risk Engine

The setup function initializes the Risk Engine and applies all necessary configurations.

import { setupCoinmeRiskEngine } from "@coinme-security/risk-sdk-js";

setupCoinmeRiskEngine({
  mode: "test",
  clientId: "client-id",
})
  .catch((error) => {
    console.error("Error setting up Risk Engine:", error);
  })
  .finally(() => {
    console.log("Risk Engine setup complete!");
  });
ℹ️

Note:

setupCoinmeRiskEngine is not sufficient in and of itself to use the risk SDK; this call is to be made when your app starts up in order to initialize the risk engine. There are other conditions which will require you to update additional parameters dynamically during the user session, such as when a user starts a high-risk action like a transaction, after a user has onboarded and now there is a customerId, etc. In these cases, use updateCoinmeRiskEngine.

ℹ️

Key Takeaway: When should I use this?

You should call setupCoinmeRiskEngine when your application instantiates.

⚠️ You will need two clientIds, one for your development builds and one for your prod builds; you may obtain these from the Coinme business development team. It is very important that you pass the correct mode and clientId properties into the risk engine based on development or production usage, otherwise you may not stream your behavioral data to the correct environment, which can severely impact the risk engine’s ability to assess risk. This would ultimately negatively impact your transaction approvals.

Get Current Configuration

To check which risk parameters are applied, use:

import { getCoinmeRiskEngineConfig } from "@coinme-security/risk-sdk-js";

const config = getCoinmeRiskEngineConfig();
console.log(config);
ℹ️

Note:

The Risk Engine configuration is only available after setup completes.

Update Coinme Risk Engine Configuration

While setup handles initial configuration, you can and should manually update specific parameters when needed. An example would be after a user has onboarded or logged in, as at this point you will have a customerId available to you; this helps the risk engine associate user behavior with your user.

Another example is when you wish to update the flow identifier being sent to the risk engine. This is necessary so that when your user is entering a specific flow in your app such as onboarding, linking a payment method, or transacting, these special activities will be properly tagged; the risk engine examines user behavior in such flows closely. Therefore, you should tag these flows by updating the risk engine config by providing a flow identifier as seen below.

ℹ️

What is a Flow Identifier?

A flow identifier is a string that acts as a tag to uniquely identify that data the risk engine is logging belongs to a contiguous and related flow of user actions.

import { updateCoinmeRiskEngine } from "@coinme-security/risk-sdk-js";

updateCoinmeRiskEngine({
  customerId: "customer-123",
  flow: "customer-onboarding",
})
  .catch((error) => {
    console.error("Error updating configuration:", error);
  })
  .finally(() => {
    console.log("Configuration updated");
  });
Flow Types

There are certain flows that are universal, and which are important to the operation of the coinme risk engine. You can use a pre-defined FlowType in these cases to ensure you are properly tagging these flows. We export a FlowType enumeration that exposes these common flows which our risk engine can understand and use when making risk decisions. This enum is structured as follows:

export enum FlowType {
  Onboarding = 'customer-onboarding',
  CardTransaction = 'card-transaction',
  CardLinking = 'payment-method-linking',
}

For maximum value, you should use the appropriate FlowType as the flow identifier when you are onboarding users, adding a payment method, or undertaking a transaction.

ℹ️

Why Use Flow Identifiers?

Flow identifiers help group multiple actions into a single session so that risk is assessed based on contextual user behavior. Instead of analyzing each interaction separately, the risk engine can detect patterns within a specific user journey.

For example:

  • If a user enters payment details too quickly after onboarding, this might indicate a scripted attack rather than a real person.
  • If a user switches IP addresses midway through a transaction, it could indicate a fraud attempt.
  • If a user is interacting normally but suddenly switches to rapid inputs, the system can adapt its risk evaluation in real time.

By tagging actions with the correct FlowType, your application provides the risk engine with the necessary context to assess transactional legitimacy.

⚠️

Important:

The Coinme risk engine requires the specific flow identifiers exposed by the risk SDK for any of these pre-defined flow types; if you do not use the supported identifier, your users and transactions may not be appropriately scored and you will be at risk of high denial rates for your transactions.

Usage Examples

Each example demonstrates when and how to use updateCoinmeRiskEngine with a specific flow type.

Example 1: Onboarding Flow

When a new user signs up, you must tag their session as onboarding so the risk engine can monitor suspicious activities.

import { updateCoinmeRiskEngine, FlowType } from "@coinme-security/risk-sdk-js";

updateCoinmeRiskEngine({
  customerId: "new-user-456",
  flow: FlowType.Onboarding,
})
  .catch((error) => {
    console.error("Error updating configuration:", error);
  })
  .finally(() => {
    console.log("User onboarding flow tracked.");
  });
ℹ️

When to use?

Call this when the user starts the signup process.

Example 2: After Onboarding or Sign-in

After a new user finishes signing up, or after a user has signed in, you must update the risk engine with their userID so that data can now be associated with the user rather than a session. This allows the risk engine to aggregate and interpret data over time.

import { updateCoinmeRiskEngine, FlowType } from "@coinme-security/risk-sdk-js";

updateCoinmeRiskEngine({
  customerId: "user-456",
})
  .catch((error) => {
    console.error("Error updating configuration:", error);
  })
  .finally(() => {
    console.log("User ID now tracked.");
  });
ℹ️

When to use?

Call this right after the user completes the signup or login process and the user’s permanent ID is known.

Example 3: Linking a New Card

If a user is adding a new payment method, this is a high-risk action that must be monitored.

import { updateCoinmeRiskEngine, FlowType } from "@coinme-security/risk-sdk-js";

updateCoinmeRiskEngine({
  customerId: "user-789",
  flow: FlowType.CardLinking,
})
  .catch((error) => {
    console.error("Error updating configuration:", error);
  })
  .finally(() => {
    console.log("Card linking flow tracked.");
  });
ℹ️

When to use?

Call this when the user enters a process to add a payment method.

Example 4: Processing a Card Transaction

When a user makes a purchase or transaction, you should explicitly tag it.

import { updateCoinmeRiskEngine, FlowType } from "@coinme-security/risk-sdk-js";

updateCoinmeRiskEngine({
  customerId: "user-123",
  flow: FlowType.CardTransaction,
})
  .catch((error) => {
    console.error("Error updating configuration:", error);
  })
  .finally(() => {
    console.log("Card transaction flow tracked.");
  });
ℹ️

When to use?

Call this when the user enters a transactional flow such as when they start a buy or sell transaction.

⚠️

Proper Use:

The updateCoinmeRiskEngine function is designed to modify the risk engine's configuration after the initial setup. However, since both setupCoinmeRiskEngine and updateCoinmeRiskEngine are asynchronous, calling them sequentially without ensuring the setup is complete may cause the update function to override the initial configuration.

How to Update Correctly
  • Ensure that setupCoinmeRiskEngine is completed before calling updateCoinmeRiskEngine.
  • If calling both on the first render (e.g., in a React setup), chain them properly using await or a state check.
  • Calling updateCoinmeRiskEngine before setupCoinmeRiskEngine finishes may lead to an incomplete or overridden configuration.

Example: Correct Usage - Await the Setup Before Updating

async function initializeRiskEngine() {
  await setupCoinmeRiskEngine({
    mode: "test",
    clientId: "client-id",
  });

  console.log("Setup complete:", getCoinmeRiskEngineConfig());

  await updateCoinmeRiskEngine({
    customerId: "[email protected]",
    flow: "flow-id",
  });

  console.log("Update complete:", getCoinmeRiskEngineConfig());
}

initializeRiskEngine();
ℹ️

Why is this correct?

  • Ensures setup completes before update can be called

Example: Incorrect Usage - Running Setup and Update in Parallel

setupCoinmeRiskEngine({
  mode: "test",
  clientId: "client-id",
});

updateCoinmeRiskEngine({
  customerId: "[email protected]",
  flow: "flow-id",
});
ℹ️

Why is this wrong?

  • updateCoinmeRiskEngine may execute before setupCoinmeRiskEngine completes.
  • The update call might override important setup details.
  • Leads to unpredictable behavior in the risk engine configuration.
ℹ️

Key Takeaway: When should I use this?

You should call updateCoinmeRiskEngine:

  • After a user has onboarded or logged in, and you have a customerId
  • By updating the risk engine with the customerId, you ensure that the risk engine can understand the user’s behavior over time, which leads to better risk modeling.
  • When a user begins a flow that needs to be explicitly identified, such as onboarding, linking a payment method, or transacting.
  • These are key actions that should be tagged with the correct flow identifier.

Tagging Elements

You can add Risk attributes to elements, components, or strings with the addCoinmeRiskTag function. The risk engine SDK automatically detects these tags and will flow behavioral metrics into the risk engine from any tagged entities automatically.

Examples:

  • Returning a pre-tagged HTML element:
import { addCoinmeRiskTag } from "@coinme-security/risk-sdk-js";

// Using a raw HTML string
const elementAsString = addCoinmeRiskTag({
  element: '<div>Hello, World!</div>',
  riskIdentifier: 'my-element',
});

console.log(elementAsString); // Outputs a div with the risk data attribute 'my-element' added.
  • Tagging an existing DOM element:
import { addCoinmeRiskTag } from "@coinme-security/risk-sdk-js";

// Using an existing DOM element
const divElement = document.createElement('div');

divElement.textContent = 'Hello, World!';

const taggedElement = addCoinmeRiskTag({ element: divElement, riskIdentifier: 'my-element' });

console.log(taggedElement.outerHTML); // Outputs a div with the risk data attribute 'my-element' added.
  • Tagging a React-Like object:
import { addCoinmeRiskTag } from "@coinme-security/risk-sdk-js";

// Tagging a React/Vue-style object
const reactLikeObject = {
  type: 'div',
  props: { children: 'Hello, World!' },
};

const taggedObject = addCoinmeRiskTag({ element: reactLikeObject, riskIdentifier: 'my-element' });

console.log(taggedObject); 
// Outputs a react / vue style object with the risk data attribute 'my-element' added.

Core concepts

Client ID Requirement

⚠️

Important:

You must provide your clientId to use the SDK. If you don't have your clientId, contact Coinme business development team.

The clientId uniquely identifies your partner integration within the Risk Engine.

  • It is provided by Coinme during onboarding.
  • Usually shared with other credentials like auth tokens or access scopes.
  • Without it, the SDK will throw an error and refuse to initialize.

Understanding sessionKey

The sessionKey is a unique identifier for tracking a specific user session.

⚠️

In-Memory Only:

The SDK does not persist session keys to localStorage, sessionStorage, or cookies. The session key is only held in memory. On page refresh, the key is lost unless you persist and rehydrate it.

BehaviorOutcome
Provide sessionKey in setupUsed & cached in memory
Provide sessionKey in updateOverrides & caches in memory
No sessionKey provided, stored key existsStored key reused automatically
No sessionKey provided, no stored keyAuto-generated using FingerprintJS & cached
Call getSessionTag()webSessionID from server becomes the cached sessionKey
Call clearSessionKey()Clears the in-memory key
⚠️

Important:

When you call getSessionTag(), the returned webSessionID automatically becomes the active session key. All subsequent calls to updateCoinmeRiskEngine() will use this session key unless you explicitly provide a different one.

ℹ️

Why this matters:

It is essential that the Risk Engine use the session tag returned by this endpoint once it is called. If you change the session key after this call is made, risk metrics will not be properly associated with your user. When you call getSessionTag(), you are signifying that you want Coinme to track your user's session — your own session ID is no longer relevant to this tracking.

ℹ️

Persisting across page reloads:

If you want the session key to persist across browser refreshes, you are responsible for storage:

  1. Store the webSessionID we return (e.g., in localStorage or sessionStorage)
  2. On subsequent page loads, pass it to updateCoinmeRiskEngine({ sessionKey: storedKey }) instead of calling getSessionTag() again
⚠️

Call getSessionTag() only once per user session.

Each call to getSessionTag() creates a new risk assessment session on the server. Calling it multiple times per user session will fragment risk data across multiple sessions and significantly degrade the risk engine's ability to accurately assess your users. It is your responsibility to ensure you only call this once per logical session.

Clearing the sessionKey

import { clearSessionKey } from "@coinme-security/risk-sdk-js";

clearSessionKey();
⚠️

This only clears the in-memory key. Use this in SPAs when:

  • Logging out users (without a page refresh)
  • Switching accounts
  • Resetting state for tests

For non-SPA apps or full page reloads, the in-memory key is cleared automatically.

Typical Session Flow Example

// Setup with auto-generated sessionKey
await setupCoinmeRiskEngine({
  mode: 'prod',
  clientId: 'client-id',
});

// Later — Update without providing sessionKey (uses stored one)
await updateCoinmeRiskEngine({
  flow: 'customer-onboarding',
});

// On session end (e.g., logout in a SPA)
clearSessionKey();

// Start new user/session
await setupCoinmeRiskEngine({
  mode: 'prod',
  clientId: 'client-id',
});

Session Flow with getSessionTag (Recommended for Transactions)

import { 
  setupCoinmeRiskEngine, 
  getSessionTag, 
  updateCoinmeRiskEngine,
  clearSessionKey 
} from "@coinme-security/risk-sdk-js";

const SESSION_KEY_STORAGE = 'coinme_session_key';

async function initializeRiskEngine() {
  // Always setup first
  await setupCoinmeRiskEngine({
    mode: 'prod',
    clientId: 'client-id',
  });

  // Check if we have a persisted session key
  const persistedSessionKey = sessionStorage.getItem(SESSION_KEY_STORAGE);

  if (persistedSessionKey) {
    // Rehydrate with the persisted session key
    await updateCoinmeRiskEngine({
      sessionKey: persistedSessionKey,
    });
  } else {
    // First time in this session — get a new session tag from the server
    const sessionData = await getSessionTag({
      apiBaseUrl: 'https://api.example.com',
      fingerprint: 'device-fingerprint',
      customerId: 'customer-123',
      additionalHeaders: {
        'x-partner-id': 'your-partner-id',
        'x-ramp-id': 'your-ramo-id', // onlyt needed for ramp partners
      },
    });

    // Persist for page reloads
    sessionStorage.setItem(SESSION_KEY_STORAGE, sessionData.webSessionID);
  }
}

// On logout or session end (SPA only — page refresh clears automatically)
function endSession() {
  sessionStorage.removeItem(SESSION_KEY_STORAGE);
  clearSessionKey();
}

API Reference

The Coinme Risk Engine SDK provides the following functions for interacting with the Risk Engine.

You can find detailed information about each function below or in the API Reference.

setupCoinmeRiskEngine

Sets up the Coinme Risk Engine with the provided options.

Parameters:

ParamTypeRequiredDescription
mode'test' | 'prod'Operating environment
clientIdstringPartner-specific risk engine client ID
partnerIdstringoptionalPartner identifier
customerIdstringoptionalCustomer identifier
sessionKeystringoptionalCustom session tracking key
flowstring | FlowTypeoptionalFlow context

Example:

import { setupCoinmeRiskEngine } from "@coinme-security/risk-sdk-js";

setupCoinmeRiskEngine({ mode: "test", clientId: "client-id" })
  .catch((error) => {
    console.error("Error setting up Risk Engine:", error);
  })
  .finally(() => {
    console.log("Risk Engine setup complete!");
  });

getCoinmeRiskEngineConfig

Retrieves the latest risk assessment settings applied to the current session.

Returns:

  • Partial<RiskEngineConfig>: An object containing the current Risk Engine configuration. All fields are optional and include: partnerId, customerId, sessionKey, flow, parentSessionKey, enableBiometrics, enableGeoLocation, enablePortScanning.
  • If no configuration has been set, it returns {}.

Example:

import { getCoinmeRiskEngineConfig } from "@coinme-security/risk-sdk-js";

const config = getCoinmeRiskEngineConfig();
console.log(config); // Outputs: { partnerId: "...", sessionKey: "...", ... }

updateCoinmeRiskEngine

Updates the Coinme risk assessment settings for the current session. This ensures that risk evaluations, such as device fingerprinting and geolocation tracking, are correctly applied.

Parameters:

ParamTypeRequiredDescription
partnerIdstringoptionalPartner identifier
customerIdstringoptionalCustomer identifier
sessionKeystringoptionalOverride session key
flowstring | FlowTypeoptionalFlow context
parentSessionKeystringoptionalParent session key
enableBiometricsbooleanoptionalEnable biometric signals
enableGeoLocationbooleanoptionalEnable geo-location
enablePortScanningbooleanoptionalEnable port scanning

Example:

import { updateCoinmeRiskEngine } from "@coinme-security/risk-sdk-js";

updateCoinmeRiskEngine({
  customerId: "customer-123",
  flow: "onboarding",
})
  .catch((error) => {
    console.error("Error updating configuration:", error);
  })
  .finally(() => {
    console.log("Configuration updated");
  });

addCoinmeRiskTag

Enhances an element, component, or string representation of HTML by tagging the element with a risk tag. The risk engine SDK automatically detects these tags and will flow metrics into the risk engine from any tagged entities automatically.

Parameters:

PropTypeRequiredDescription
elementHTMLElement | string | objectTarget element
riskIdentifierstringUnique risk tag

Returns:

  • The same element with the risk tag applied.

Example:

import { addCoinmeRiskTag } from "@coinme-security/risk-sdk-js";

const element = addCoinmeRiskTag({
  element: '<div>Hello, World!</div>',
  riskIdentifier: 'my-element',
});

console.log(element); // Outputs a div tagged with the specified risk tag

withCoinmeRiskTag

Creates a higher-order component that adds a risk tag to the wrapped component's output. The tagging behavior depends on what the component returns:

  • String: the string output is wrapped in a new <div data-sardine-id="..."> element.
  • HTMLElement: the data-sardine-id attribute is added directly to the element.
  • Object with props (React/Vue-style): data-sardine-id is added to the props object.

Parameters:

ParamTypeRequiredDescription
ComponentfunctionThe component function to wrap.
idstringUnique risk tag to apply.

Returns:

  • A wrapped component with the risk tag attribute added to props or its equivalent.

Examples:

Wrapping a simple component:

import { withCoinmeRiskTag } from "@coinme-security/risk-sdk-js";

const MyComponent = (props) => `<div>${props.text}</div>`;

const TaggedComponent = withCoinmeRiskTag(MyComponent, 'my-element');

console.log(TaggedComponent({ text: 'Hello, world!' }));
// The string output is wrapped in a new tagged div:
// <div data-sardine-id="my-element"><div>Hello, world!</div></div>

Wrapping a object-based component:

import { withCoinmeRiskTag } from "@coinme-security/risk-sdk-js";

const MyObjectComponent = (props) => ({
  type: 'div',
  props: { children: props.text },
});

const WrappedObject = withCoinmeRiskTag(MyObjectComponent, 'object-component');

console.log(WrappedObject({ text: 'Hello, world!' }));
// Outputs an object tagged with the specified risk tag

getSessionTag

Retrieves the Sardine session tag data from the public /pub/get-session-tag endpoint. This call obtains the session information needed for transaction risk assessment. Upon successful retrieval, the webSessionID is automatically used to update the Sardine configuration and is stored as the active session key for all subsequent SDK calls.

Parameters:

ParamTypeRequiredDescription
apiBaseUrlstringThe base URL of the API endpoint
fingerprintstringThe device fingerprint to include in request headers
customerIdstringThe customer ID, sent as the accountId query parameter
additionalHeadersRecord<string, string>Additional headers. Must include x-partner-id with the value provided by Coinme business development. Example: additionalHeaders: { 'X-Partner-ID': 'partner-123' }
timeoutnumberoptionalRequest timeout in milliseconds (default: 10000)

Returns:

  • Promise<SessionTagData>: A promise that resolves with the session tag data containing webSessionID and orgID. The Sardine configuration is automatically updated with the webSessionID as the session key.

Example:

import { getSessionTag } from "@coinme-security/risk-sdk-js";

const sessionData = await getSessionTag({
  apiBaseUrl: 'https://api.example.com',
  fingerprint: 'device-fingerprint-value',
  customerId: 'customer-123',
  additionalHeaders: {
    'x-partner-id': 'your-partner-id',
  },
});

// The webSessionID is automatically set in Sardine configuration
const webSessionId = sessionData.webSessionID;
const orgId = sessionData.orgID;
ℹ️

When to use?

Call this before initiating buy/sell transactions to retrieve the session tag and automatically configure Sardine with the proper session key. The returned webSessionID can also be passed to transaction endpoints if needed.

⚠️

Important:

After calling getSessionTag(), the webSessionID becomes the stored session key. You do not need to pass it to subsequent updateCoinmeRiskEngine() calls — the SDK will automatically use it. If you need to override this behavior, explicitly pass a different sessionKey to updateCoinmeRiskEngine().