Skip to main content

After Checkout Verification

App Under Review

The Real ID app is currently being reviewed by the BigCommerce App Marketplace team. Until the one-click install is available, please follow these manual setup steps. Contact us to get started.

After checkout verification allows customers to complete their order first, then verify their ID on the order confirmation page. This is the recommended approach for most stores.

How it works

  1. Customer shops and completes checkout normally
  2. On the order confirmation page, they see the ID verification prompt
  3. Customer uploads their ID and completes verification
  4. Order is held until verification is complete

Setup

Step 1: Create API Credentials

You'll need to create API credentials in your BigCommerce dashboard:

  1. Log in to your BigCommerce admin panel
  2. Go to Settings > API > API Accounts
  3. Click Create API Account > Create V2/V3 API Token
  4. Name it "Real ID"
  5. Under OAuth Scopes, enable the following:
    • Customers: Modify
    • Orders: Modify
    • Products: Read-only
    • Storefront API Tokens: Manage
    • Carts: Modify
    • Information & settings: Read-only
  6. Click Save
  7. Important: Copy and save your API credentials (Client ID, Client Secret, and Access Token). You won't be able to see the Access Token again.

Step 2: Save API Credentials in the Real ID App

  1. Go to app.getverdict.com
  2. Log in or create an account (contact us if you need access)
  3. Add your BigCommerce store
  4. Enter your API credentials from Step 1
  5. Configure your verification settings

Step 3: Add the Real ID Script

Add the Real ID script to your store using Script Manager:

  1. In your BigCommerce admin, go to Storefront > Script Manager
  2. Click Create a Script
  3. Fill in the following:
    • Name: Real ID Verification
    • Description: ID verification on order confirmation
    • Location on page: Footer
    • Select pages where script will be added: Order Confirmation
    • Script category: Essential
    • Script type: URL
    • Script URL: https://bc-flow.getverdict.com/assets/index.js
  4. Click Save

Step 4: Add Order Data to Your Theme

The Real ID script needs order information to work. Add this code snippet to your theme:

  1. In your BigCommerce admin, go to Storefront > Themes
  2. Find your active theme and click Advanced > Edit Theme Files
  3. Navigate to templates/pages/order-confirmation.html
  4. Find the line that says {{{footer.scripts}}}
  5. Above that line, paste this code:
<script type="text/javascript">
window.realIdOrderData = {
platform: "bc",
store_hash: "{{settings.store_hash}}",
order_id: {{checkout.order.id}}
}
</script>
  1. Click Save
Where to place the code

Make sure the code snippet is placed above the {{{footer.scripts}}} line, not below it. This ensures the order data is available when Real ID loads.

Testing your setup

After completing the setup:

  1. Place a test order on your store
  2. On the order confirmation page, you should see the Real ID verification prompt
  3. Complete the verification to ensure everything works

To verify the code is installed correctly:

  1. Complete a test checkout
  2. On the order confirmation page, open your browser's developer console (F12)
  3. Type window.realIdOrderData and press Enter
  4. You should see your order information displayed

Customer experience

When after checkout verification is enabled:

  • Customers complete their purchase normally
  • The verification prompt appears on the order confirmation page
  • Customers can verify immediately or return later via email link
  • Already-verified customers are recognized automatically

Frequently Asked Questions

What happens if a customer doesn't complete verification?

The order remains in your system but is flagged as pending verification. You can configure automatic reminder emails to prompt customers to complete their verification.

Can I customize when verification is required?

Yes! You can set up triggers based on order value, specific products, customer location, and more. See the Rules documentation for details.

What if a customer closes the page before verifying?

Real ID automatically sends an email with a link to complete verification. You can also configure automatic reminders.

Do returning customers need to verify again?

No. Real ID remembers verified customers. When they return and place another order, they're automatically recognized and won't need to verify again.

Custom Trigger Scripts

For merchants who want custom trigger logic beyond the built-in options, you can create scripts that conditionally trigger ID verification using the Real ID JS SDK based on order details.

How Custom Triggers Work

  1. The Real ID SDK (Script 1) loads on order confirmation pages
  2. Your custom script (Script 2) fetches order details using the BigCommerce Storefront API
  3. If conditions are met, your script calls RealID.createFlow() to trigger verification

Setup

Script 1 - Add the Real ID SDK (you've already done this in Step 3 above):

  • Script type: URL
  • URL: https://bc-flow.getverdict.com/assets/index.js
  • Pages: Order Confirmation

Script 2 - Add your custom trigger script:

  1. In BigCommerce admin, go to Storefront > Script Manager
  2. Click Create a Script
  3. Fill in the following:
    • Name: Real ID Custom Trigger
    • Description: Custom ID verification trigger
    • Location on page: Footer
    • Select pages where script will be added: Order Confirmation
    • Script category: Essential
    • Script type: Script
  4. Paste one of the example scripts below
  5. Click Save
Prerequisites

These scripts require the realIdOrderData object from Step 4 above. Make sure you've added the order data snippet to your theme's order-confirmation.html template before using custom triggers.

Using the Store Hash

Unlike the checkout page, the order confirmation page already has the store hash available via window.realIdOrderData.store_hash (set by your theme template). The examples below use this value directly.

Example 1: Verify All Orders

The simplest trigger - requires verification for every order.

<script>
// Helper: Wait for an element to appear in the DOM
function waitForSelector(selector, timeoutMs) {
timeoutMs = timeoutMs || 30000;
return new Promise(function(resolve) {
var existing = document.querySelector(selector);
if (existing) {
console.log('Real ID: Element ' + selector + ' already exists');
resolve(existing);
return;
}
console.log('Real ID: Waiting for element ' + selector);
var observer = new MutationObserver(function(mutations, obs) {
var element = document.querySelector(selector);
if (element) {
obs.disconnect();
console.log('Real ID: Element ' + selector + ' found');
resolve(element);
}
});
observer.observe(document.body, {
childList: true,
subtree: true
});
setTimeout(function() {
observer.disconnect();
console.log('Real ID: Timeout waiting for ' + selector);
resolve(null);
}, timeoutMs);
});
}

// Real ID - Verify all orders
(async function() {
console.log('Real ID: Initializing verification for all orders');

// Check for order data
if (!window.realIdOrderData || !window.realIdOrderData.order_id) {
console.log('Real ID: No order data found, skipping verification');
return;
}

console.log('Real ID: Order ID ' + window.realIdOrderData.order_id);

try {
// Fetch order details from Storefront API
var response = await fetch('/api/storefront/orders/' + window.realIdOrderData.order_id);
var order = await response.json();

// Wait for the order confirmation heading to appear
var heading = await waitForSelector('[data-test="order-confirmation-heading"]');
if (heading) {
console.log('Real ID: Triggering verification flow');
RealID.createFlow({
target: '[data-test="order-confirmation-heading"]',
mode: "full",
shopName: window.realIdOrderData.store_hash,
email: order.billingAddress.email,
firstName: order.billingAddress.firstName,
lastName: order.billingAddress.lastName
});
} else {
console.log('Real ID: Order confirmation heading not found, skipping verification');
}
} catch (e) {
console.error('Real ID: Error fetching order', e);
}
})();
</script>

Example 2: Verify Orders Over a Certain Amount

Only trigger verification when order total exceeds a threshold.

<script>
// Helper: Wait for an element to appear in the DOM
function waitForSelector(selector, timeoutMs) {
timeoutMs = timeoutMs || 30000;
return new Promise(function(resolve) {
var existing = document.querySelector(selector);
if (existing) { resolve(existing); return; }
var observer = new MutationObserver(function(mutations, obs) {
var element = document.querySelector(selector);
if (element) { obs.disconnect(); resolve(element); }
});
observer.observe(document.body, { childList: true, subtree: true });
setTimeout(function() { observer.disconnect(); resolve(null); }, timeoutMs);
});
}

// Real ID - Verify orders over $100
(async function() {
var MINIMUM_AMOUNT = 100; // Customize this value
console.log('Real ID: Checking order total (minimum: $' + MINIMUM_AMOUNT + ')');

// Check for order data
if (!window.realIdOrderData || !window.realIdOrderData.order_id) {
console.log('Real ID: No order data found');
return;
}

try {
// Fetch order details from Storefront API
var response = await fetch('/api/storefront/orders/' + window.realIdOrderData.order_id);
var order = await response.json();

console.log('Real ID: Order total is $' + order.orderAmount);

if (order.orderAmount < MINIMUM_AMOUNT) {
console.log('Real ID: Order below threshold, skipping verification');
return;
}

console.log('Real ID: Order exceeds threshold, triggering verification');

// Wait for the order confirmation heading
var heading = await waitForSelector('[data-test="order-confirmation-heading"]');
if (heading) {
RealID.createFlow({
target: '[data-test="order-confirmation-heading"]',
mode: "full",
shopName: window.realIdOrderData.store_hash,
email: order.billingAddress.email,
firstName: order.billingAddress.firstName,
lastName: order.billingAddress.lastName
});
}
} catch (e) {
console.error('Real ID: Error fetching order', e);
}
})();
</script>

Example 3: Verify Orders to Specific US States

Only trigger verification for orders shipped to certain states.

<script>
// Helper: Wait for an element to appear in the DOM
function waitForSelector(selector, timeoutMs) {
timeoutMs = timeoutMs || 30000;
return new Promise(function(resolve) {
var existing = document.querySelector(selector);
if (existing) { resolve(existing); return; }
var observer = new MutationObserver(function(mutations, obs) {
var element = document.querySelector(selector);
if (element) { obs.disconnect(); resolve(element); }
});
observer.observe(document.body, { childList: true, subtree: true });
setTimeout(function() { observer.disconnect(); resolve(null); }, timeoutMs);
});
}

// Real ID - Verify orders shipping to specific US states
(async function() {
var REQUIRED_STATES = ['CA', 'NY', 'TX']; // Customize this list
console.log('Real ID: Checking shipping state (required: ' + REQUIRED_STATES.join(', ') + ')');

// Check for order data
if (!window.realIdOrderData || !window.realIdOrderData.order_id) {
console.log('Real ID: No order data found');
return;
}

try {
// Fetch order details from Storefront API
var response = await fetch('/api/storefront/orders/' + window.realIdOrderData.order_id);
var order = await response.json();

// Get shipping consignment for address info
var shippingConsignment = order.consignments &&
order.consignments.shipping &&
order.consignments.shipping[0];

// Note: shipping consignment may not have stateOrProvinceCode, but billingAddress does
// Use shipping consignment for display, but prefer billingAddress for state code matching
var displayAddress = shippingConsignment || order.billingAddress;

if (!displayAddress) {
console.log('Real ID: No address found');
return;
}

console.log('Real ID: Shipping to ' + displayAddress.stateOrProvince + ', ' + displayAddress.country);

// Get state code - prefer billingAddress which reliably has stateOrProvinceCode
var stateCode = (order.billingAddress && order.billingAddress.stateOrProvinceCode) ||
(shippingConsignment && shippingConsignment.stateOrProvinceCode) ||
displayAddress.stateOrProvince;
var countryCode = (order.billingAddress && order.billingAddress.countryCode) ||
(shippingConsignment && shippingConsignment.countryCode) ||
displayAddress.country;

// Check if US order
var isUS = countryCode === 'US' || countryCode === 'United States';
if (!isUS) {
console.log('Real ID: Non-US order, skipping verification');
return;
}

// Check state
if (!REQUIRED_STATES.includes(stateCode)) {
console.log('Real ID: State code "' + stateCode + '" not in required list, skipping verification');
return;
}

console.log('Real ID: State matches, triggering verification');

// Wait for the order confirmation heading
var heading = await waitForSelector('[data-test="order-confirmation-heading"]');
if (heading) {
RealID.createFlow({
target: '[data-test="order-confirmation-heading"]',
mode: "full",
shopName: window.realIdOrderData.store_hash,
email: order.billingAddress.email,
firstName: order.billingAddress.firstName,
lastName: order.billingAddress.lastName
});
}
} catch (e) {
console.error('Real ID: Error fetching order', e);
}
})();
</script>

Example 4: Verify Orders with Specific Product Categories

Only trigger verification when the order contains products from certain categories.

<script>
// Helper: Wait for an element to appear in the DOM
function waitForSelector(selector, timeoutMs) {
timeoutMs = timeoutMs || 30000;
return new Promise(function(resolve) {
var existing = document.querySelector(selector);
if (existing) { resolve(existing); return; }
var observer = new MutationObserver(function(mutations, obs) {
var element = document.querySelector(selector);
if (element) { obs.disconnect(); resolve(element); }
});
observer.observe(document.body, { childList: true, subtree: true });
setTimeout(function() { observer.disconnect(); resolve(null); }, timeoutMs);
});
}

// Real ID - Verify orders containing products from specific categories
(async function() {
var REQUIRED_CATEGORY_IDS = [23, 45, 67]; // Customize with your category IDs
console.log('Real ID: Checking product categories (required IDs: ' + REQUIRED_CATEGORY_IDS.join(', ') + ')');

// Check for order data
if (!window.realIdOrderData || !window.realIdOrderData.order_id) {
console.log('Real ID: No order data found');
return;
}

try {
// Fetch order details from Storefront API
var response = await fetch('/api/storefront/orders/' + window.realIdOrderData.order_id);
var order = await response.json();

// Extract product IDs from order.lineItems (not from consignments)
// Note: consignments.shipping[].lineItems only contains { id } references
// Full product details are in order.lineItems.physicalItems
var productIds = [];
var physicalItems = order.lineItems && order.lineItems.physicalItems || [];
physicalItems.forEach(function(item) {
if (item.productId) {
productIds.push(item.productId);
}
});

if (productIds.length === 0) {
console.log('Real ID: No products found in order');
return;
}

console.log('Real ID: Checking categories for products: ' + productIds.join(', '));

// Fetch Storefront API token from Real ID
var tokenResponse = await fetch('https://real-id.getverdict.com/api/bc/shops/' + window.realIdOrderData.store_hash + '/storefront-token');
var tokenData = await tokenResponse.json();
if (!tokenData.token) {
console.log('Real ID: Could not fetch storefront token');
return;
}

// Check product categories via GraphQL
var query = '{ site { products(entityIds: [' + productIds.join(',') + '], first: 50) { edges { node { entityId categories { edges { node { entityId } } } } } } } }';
var gqlResponse = await fetch('/graphql', {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + tokenData.token
},
body: JSON.stringify({ query: query })
});
var gqlData = await gqlResponse.json();

var products = gqlData.data && gqlData.data.site && gqlData.data.site.products && gqlData.data.site.products.edges || [];
var shouldTrigger = products.some(function(productEdge) {
var categories = productEdge.node.categories && productEdge.node.categories.edges || [];
return categories.some(function(catEdge) {
return REQUIRED_CATEGORY_IDS.includes(catEdge.node.entityId);
});
});

if (!shouldTrigger) {
console.log('Real ID: No products match required categories, skipping verification');
return;
}

console.log('Real ID: Found products in required categories, triggering verification');

// Wait for the order confirmation heading
var heading = await waitForSelector('[data-test="order-confirmation-heading"]');
if (heading) {
RealID.createFlow({
target: '[data-test="order-confirmation-heading"]',
mode: "full",
shopName: window.realIdOrderData.store_hash,
email: order.billingAddress.email,
firstName: order.billingAddress.firstName,
lastName: order.billingAddress.lastName
});
}
} catch (e) {
console.error('Real ID: Error checking product categories', e);
}
})();
</script>
Finding Category IDs

To find your category IDs, go to Products > Product Categories in your BigCommerce admin. Click on a category - the ID is shown in the URL (e.g., /manage/categories/23 means the ID is 23).

Example 5: Verify Orders with Products Having Custom Field

Only trigger verification when the order contains products that have a specific custom field set.

<script>
// Helper: Wait for an element to appear in the DOM
function waitForSelector(selector, timeoutMs) {
timeoutMs = timeoutMs || 30000;
return new Promise(function(resolve) {
var existing = document.querySelector(selector);
if (existing) { resolve(existing); return; }
var observer = new MutationObserver(function(mutations, obs) {
var element = document.querySelector(selector);
if (element) { obs.disconnect(); resolve(element); }
});
observer.observe(document.body, { childList: true, subtree: true });
setTimeout(function() { observer.disconnect(); resolve(null); }, timeoutMs);
});
}

// Real ID - Verify orders with products that have "id_required" custom field
(async function() {
var CUSTOM_FIELD_NAME = 'id_required'; // Customize field name if needed
console.log('Real ID: Checking for products with custom field "' + CUSTOM_FIELD_NAME + '"');

// Check for order data
if (!window.realIdOrderData || !window.realIdOrderData.order_id) {
console.log('Real ID: No order data found');
return;
}

try {
// Fetch order details from Storefront API
var response = await fetch('/api/storefront/orders/' + window.realIdOrderData.order_id);
var order = await response.json();

// Extract product IDs from order.lineItems (not from consignments)
// Note: consignments.shipping[].lineItems only contains { id } references
// Full product details are in order.lineItems.physicalItems
var productIds = [];
var physicalItems = order.lineItems && order.lineItems.physicalItems || [];
physicalItems.forEach(function(item) {
if (item.productId) {
productIds.push(item.productId);
}
});

if (productIds.length === 0) {
console.log('Real ID: No products found in order');
return;
}

console.log('Real ID: Checking custom fields for products: ' + productIds.join(', '));

// Fetch Storefront API token from Real ID
var tokenResponse = await fetch('https://real-id.getverdict.com/api/bc/shops/' + window.realIdOrderData.store_hash + '/storefront-token');
var tokenData = await tokenResponse.json();
if (!tokenData.token) {
console.log('Real ID: Could not fetch storefront token');
return;
}

// Check product custom fields via GraphQL
var query = '{ site { products(entityIds: [' + productIds.join(',') + '], first: 50) { edges { node { entityId customFields { edges { node { name value } } } } } } } }';
var gqlResponse = await fetch('/graphql', {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + tokenData.token
},
body: JSON.stringify({ query: query })
});
var gqlData = await gqlResponse.json();

var products = gqlData.data && gqlData.data.site && gqlData.data.site.products && gqlData.data.site.products.edges || [];
var shouldTrigger = products.some(function(productEdge) {
var customFields = productEdge.node.customFields && productEdge.node.customFields.edges || [];
return customFields.some(function(fieldEdge) {
return fieldEdge.node.name === CUSTOM_FIELD_NAME &&
fieldEdge.node.value.toLowerCase() === 'true';
});
});

if (!shouldTrigger) {
console.log('Real ID: No products have "' + CUSTOM_FIELD_NAME + '" = true, skipping verification');
return;
}

console.log('Real ID: Found products requiring ID verification, triggering flow');

// Wait for the order confirmation heading
var heading = await waitForSelector('[data-test="order-confirmation-heading"]');
if (heading) {
RealID.createFlow({
target: '[data-test="order-confirmation-heading"]',
mode: "full",
shopName: window.realIdOrderData.store_hash,
email: order.billingAddress.email,
firstName: order.billingAddress.firstName,
lastName: order.billingAddress.lastName
});
}
} catch (e) {
console.error('Real ID: Error checking product custom fields', e);
}
})();
</script>
Creating Custom Fields

To add a custom field to a product:

  1. Go to Products > View in BigCommerce admin
  2. Edit the product
  3. Scroll to Custom Fields
  4. Add a field with name id_required and value true
  5. Save the product

Example 6: Specific State AND Product Category (Combined)

Trigger verification only when BOTH conditions are met: shipped to California AND order contains products from specific categories.

<script>
// Helper: Wait for an element to appear in the DOM
function waitForSelector(selector, timeoutMs) {
timeoutMs = timeoutMs || 30000;
return new Promise(function(resolve) {
var existing = document.querySelector(selector);
if (existing) { resolve(existing); return; }
var observer = new MutationObserver(function(mutations, obs) {
var element = document.querySelector(selector);
if (element) { obs.disconnect(); resolve(element); }
});
observer.observe(document.body, { childList: true, subtree: true });
setTimeout(function() { observer.disconnect(); resolve(null); }, timeoutMs);
});
}

// Real ID - Verify orders shipping to CA with products in specific categories
(async function() {
var REQUIRED_STATE = 'CA'; // State code to require verification
var REQUIRED_CATEGORY_IDS = [23, 45, 67]; // Customize with your category IDs
console.log('Real ID: Checking for state=' + REQUIRED_STATE + ' AND categories=' + REQUIRED_CATEGORY_IDS.join(', '));

// Check for order data
if (!window.realIdOrderData || !window.realIdOrderData.order_id) {
console.log('Real ID: No order data found');
return;
}

try {
// Step 1: Fetch order and check shipping state
var response = await fetch('/api/storefront/orders/' + window.realIdOrderData.order_id);
var order = await response.json();

// Get shipping consignment for address info
var shippingConsignment = order.consignments &&
order.consignments.shipping &&
order.consignments.shipping[0];

// Note: shipping consignment may not have stateOrProvinceCode, but billingAddress does
// Use shipping consignment for display, but prefer billingAddress for state code matching
var displayAddress = shippingConsignment || order.billingAddress;

if (!displayAddress) {
console.log('Real ID: No address found');
return;
}

console.log('Real ID: Shipping to ' + displayAddress.stateOrProvince + ', ' + displayAddress.country);

// Get state code - prefer billingAddress which reliably has stateOrProvinceCode
var stateCode = (order.billingAddress && order.billingAddress.stateOrProvinceCode) ||
(shippingConsignment && shippingConsignment.stateOrProvinceCode) ||
displayAddress.stateOrProvince;
var countryCode = (order.billingAddress && order.billingAddress.countryCode) ||
(shippingConsignment && shippingConsignment.countryCode) ||
displayAddress.country;

var isUS = countryCode === 'US' || countryCode === 'United States';
var stateMatches = isUS && stateCode === REQUIRED_STATE;

if (!stateMatches) {
console.log('Real ID: State code "' + stateCode + '" does not match ' + REQUIRED_STATE + ', skipping verification');
return;
}

console.log('Real ID: State matches ' + REQUIRED_STATE + ', checking product categories...');

// Step 2: Extract product IDs from order.lineItems (not from consignments)
// Note: consignments.shipping[].lineItems only contains { id } references
// Full product details are in order.lineItems.physicalItems
var productIds = [];
var physicalItems = order.lineItems && order.lineItems.physicalItems || [];
physicalItems.forEach(function(item) {
if (item.productId) {
productIds.push(item.productId);
}
});

if (productIds.length === 0) {
console.log('Real ID: No products found in order');
return;
}

// Fetch Storefront API token from Real ID
var tokenResponse = await fetch('https://real-id.getverdict.com/api/bc/shops/' + window.realIdOrderData.store_hash + '/storefront-token');
var tokenData = await tokenResponse.json();
if (!tokenData.token) {
console.log('Real ID: Could not fetch storefront token');
return;
}

var query = '{ site { products(entityIds: [' + productIds.join(',') + '], first: 50) { edges { node { entityId categories { edges { node { entityId } } } } } } } }';
var gqlResponse = await fetch('/graphql', {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + tokenData.token
},
body: JSON.stringify({ query: query })
});
var gqlData = await gqlResponse.json();

var products = gqlData.data && gqlData.data.site && gqlData.data.site.products && gqlData.data.site.products.edges || [];
var categoryMatches = products.some(function(productEdge) {
var categories = productEdge.node.categories && productEdge.node.categories.edges || [];
return categories.some(function(catEdge) {
return REQUIRED_CATEGORY_IDS.includes(catEdge.node.entityId);
});
});

if (!categoryMatches) {
console.log('Real ID: No products in required categories, skipping verification');
return;
}

console.log('Real ID: Both conditions met! Triggering verification');

// Wait for the order confirmation heading
var heading = await waitForSelector('[data-test="order-confirmation-heading"]');
if (heading) {
RealID.createFlow({
target: '[data-test="order-confirmation-heading"]',
mode: "full",
shopName: window.realIdOrderData.store_hash,
email: order.billingAddress.email,
firstName: order.billingAddress.firstName,
lastName: order.billingAddress.lastName
});
}
} catch (e) {
console.error('Real ID: Error checking conditions', e);
}
})();
</script>

Example 7: Specific State AND Custom Field (Combined)

Trigger verification only when BOTH conditions are met: shipped to California AND order contains products with the id_verification_required custom field.

<script>
// Helper: Wait for an element to appear in the DOM
function waitForSelector(selector, timeoutMs) {
timeoutMs = timeoutMs || 30000;
return new Promise(function(resolve) {
var existing = document.querySelector(selector);
if (existing) { resolve(existing); return; }
var observer = new MutationObserver(function(mutations, obs) {
var element = document.querySelector(selector);
if (element) { obs.disconnect(); resolve(element); }
});
observer.observe(document.body, { childList: true, subtree: true });
setTimeout(function() { observer.disconnect(); resolve(null); }, timeoutMs);
});
}

// Real ID - Verify orders shipping to CA with products that have "id_verification_required" custom field
(async function() {
var REQUIRED_STATE = 'CA'; // State code to require verification
var CUSTOM_FIELD_NAME = 'id_verification_required'; // Custom field name
console.log('Real ID: Checking for state=' + REQUIRED_STATE + ' AND custom field="' + CUSTOM_FIELD_NAME + '"');

// Check for order data
if (!window.realIdOrderData || !window.realIdOrderData.order_id) {
console.log('Real ID: No order data found');
return;
}

try {
// Step 1: Fetch order and check shipping state
var response = await fetch('/api/storefront/orders/' + window.realIdOrderData.order_id);
var order = await response.json();

// Get shipping consignment for address info
var shippingConsignment = order.consignments &&
order.consignments.shipping &&
order.consignments.shipping[0];

// Note: shipping consignment may not have stateOrProvinceCode, but billingAddress does
// Use shipping consignment for display, but prefer billingAddress for state code matching
var displayAddress = shippingConsignment || order.billingAddress;

if (!displayAddress) {
console.log('Real ID: No address found');
return;
}

console.log('Real ID: Shipping to ' + displayAddress.stateOrProvince + ', ' + displayAddress.country);

// Get state code - prefer billingAddress which reliably has stateOrProvinceCode
var stateCode = (order.billingAddress && order.billingAddress.stateOrProvinceCode) ||
(shippingConsignment && shippingConsignment.stateOrProvinceCode) ||
displayAddress.stateOrProvince;
var countryCode = (order.billingAddress && order.billingAddress.countryCode) ||
(shippingConsignment && shippingConsignment.countryCode) ||
displayAddress.country;

var isUS = countryCode === 'US' || countryCode === 'United States';
var stateMatches = isUS && stateCode === REQUIRED_STATE;

if (!stateMatches) {
console.log('Real ID: State code "' + stateCode + '" does not match ' + REQUIRED_STATE + ', skipping verification');
return;
}

console.log('Real ID: State matches ' + REQUIRED_STATE + ', checking product custom fields...');

// Step 2: Extract product IDs from order.lineItems (not from consignments)
// Note: consignments.shipping[].lineItems only contains { id } references
// Full product details are in order.lineItems.physicalItems
var productIds = [];
var physicalItems = order.lineItems && order.lineItems.physicalItems || [];
physicalItems.forEach(function(item) {
if (item.productId) {
productIds.push(item.productId);
}
});

if (productIds.length === 0) {
console.log('Real ID: No products found in order');
return;
}

console.log('Real ID: Found product IDs: ' + productIds.join(', '));

// Fetch Storefront API token from Real ID
var tokenResponse = await fetch('https://real-id.getverdict.com/api/bc/shops/' + window.realIdOrderData.store_hash + '/storefront-token');
var tokenData = await tokenResponse.json();
if (!tokenData.token) {
console.log('Real ID: Could not fetch storefront token');
return;
}

var query = '{ site { products(entityIds: [' + productIds.join(',') + '], first: 50) { edges { node { entityId customFields { edges { node { name value } } } } } } } }';
var gqlResponse = await fetch('/graphql', {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + tokenData.token
},
body: JSON.stringify({ query: query })
});
var gqlData = await gqlResponse.json();

var products = gqlData.data && gqlData.data.site && gqlData.data.site.products && gqlData.data.site.products.edges || [];
var customFieldMatches = products.some(function(productEdge) {
var customFields = productEdge.node.customFields && productEdge.node.customFields.edges || [];
return customFields.some(function(fieldEdge) {
return fieldEdge.node.name === CUSTOM_FIELD_NAME &&
fieldEdge.node.value.toLowerCase() === 'true';
});
});

if (!customFieldMatches) {
console.log('Real ID: No products have "' + CUSTOM_FIELD_NAME + '" = true, skipping verification');
return;
}

console.log('Real ID: Both conditions met! Triggering verification');

// Wait for the order confirmation heading
var heading = await waitForSelector('[data-test="order-confirmation-heading"]');
if (heading) {
RealID.createFlow({
target: '[data-test="order-confirmation-heading"]',
mode: "full",
shopName: window.realIdOrderData.store_hash,
email: order.billingAddress.email,
firstName: order.billingAddress.firstName,
lastName: order.billingAddress.lastName
});
}
} catch (e) {
console.error('Real ID: Error checking conditions', e);
}
})();
</script>
Combining Conditions

These examples demonstrate AND logic - both conditions must be true. You can adapt this pattern to combine any conditions:

  • Change REQUIRED_STATE to any US state code (e.g., 'NY', 'TX')
  • Add multiple states by changing the check to ['CA', 'NY'].includes(stateCode)
  • Combine with order total checks by adding order.orderAmount >= MINIMUM_AMOUNT

Learn More

For more information about the Real ID JS SDK, including theming options and prepopulating customer data, see our JavaScript SDK documentation.