This guide has two parts:
- Part 1 runs a real verification session using a hosted Incode Webflow—no code required. You see exactly what your customers experience before you write a single line of integration code.
- Part 2 walks you through a minimal Web SDK integration that produces the same result programmatically. By the end, your app creates a session, runs ID and selfie capture, and reads the verification score.
Part 1: Create and Run a Verification Session
You will run a test verification session using a template Workflow.
Step 1.1: Create a Workflow in Dashboard
A Workflow defines the verification steps your users will go through. You need one before you can run a session.
- Log in to Dashboard and click Workflows in the left menu.
- Click New.
- In the lower left corner of the Workflow builder, click Template.
- Locate the Identity Verification template and click Use. This template comes pre-configured with the standard modules for a complete verification: Data Sharing Consent, ID Capture, ID Validation, Face Capture, Face Match, and a result condition.
- If prompted to replace what's in the canvas with the template, click Replace with template.
- In the top left corner, click Edit to give your Workflow a meaningful name.
- Click Save & Publish.
Note
You can configure Workflow-level settings and module-level settings to customize the data collected and the user experience. For this quick start, we recommend leaving the default configuration as-is.
For a deeper look at creating Workflows, using templates, and changing configuration settings, see Workflows.
Step 1.2: Copy Your Workflow ID and Onboarding URL
When the Workflow is saved, Dashboard assigns it a unique Configuration ID (also called a Workflow ID). Active Workflows also have an Onboarding URL. You will need both later in this guide. To copy them:
- In the left menu, click Workflows.
- In the Actions column for the Workflow you created, click the three-dot menu.
- Click Copy ID. This is the Workflow ID. Paste it somewhere you can easily access it later.
- Click Copy URL. This is the Onboarding URL. Paste it somewhere you can easily access it later.
You can also generate a session URL on demand from your back end. You will do this in Part 2.
Step 1.3: Complete a Test Session
- In the Actions column for the Workflow you created, click Test workflow.
- Scan the QR code on your phone to open the Onboarding.
- Go through the verification steps:
- Grant camera permission when prompted.
- Scan the front and back of a government-issued ID.
- Take a selfie when prompted.
- Wait for the result screen.
The whole process should take under two minutes.
Step 1.4: Review the Session in Dashboard
In Dashboard, click Sessions. Your test session appears. Click it to review the scores, extracted OCR data, captured images, and the overall verification result.
This is what your operations team will see for every user who goes through Onboarding.
Note
A session has three phases: capture (the customer), process (Incode), and result (your back-end decision). Part 2 shows how to drive that same flow from your own application code.
Part 2: Integrate the Web SDK
You will build a minimal web application with two parts:
- A back-end endpoint that creates an Incode session and returns the session token to your front end.
- A front-end page that loads the Incode Web SDK, runs the verification modules, and calls your back end to retrieve the score when the session finishes.
Step 2.1: Obtain Prerequisites
Before you start, make sure you have:
- Node.js 18 or higher, for the back-end server.
- A browser with camera access. Chrome is recommended. Use your phone for best capture quality.
- Your API key, API URL, and Flow configuration ID.
- The Configuration ID of the Workflow you created in Step 1.1. You can find it in the Workflow's detail view in Dashboard.
Note
The demo environment at https://demo-api.incodesmile.com is available for testing. Use it in place of your API URL until you are ready for production.
Step 2.2: Set Up Your Project
- Create a project folder and install dependencies:
mkdir incode-quickstart && cd incode-quickstart npm init -y npm install express node-fetch dotenv
- Create a
.envfile in the project root:API_URL=https://demo-api.incodesmile.com API_KEY=<YOUR_API_KEY> FLOW_ID=<YOUR_WORKFLOW_CONFIGURATION_ID> # from Step 1.1
Warning
Your API key must never appear in front-end code. This setup keeps it on the back end where it belongs.
Step 2.3: Create the Back-End Server
- Create
server.js:require('dotenv').config(); const express = require('express'); const app = express(); app.use(express.json()); app.use(express.static('public')); const API_URL = process.env.API_URL; const API_KEY = process.env.API_KEY; const FLOW_ID = process.env.FLOW_ID; // POST /start — create a new Incode session and return the token to the frontend app.post('/start', async (req, res) => { try { const response = await fetch(`${API_URL}/omni/start`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'api-version': '1.0', 'x-api-key': API_KEY, }, body: JSON.stringify({ countryCode: 'ALL', configurationId: FLOW_ID, // externalCustomerId: req.body.userId, // optional: link to your user record }), }); if (!response.ok) { throw new Error(`Incode API error: ${response.status}`); } // Return token and interviewId to the frontend. // The frontend only ever sees the token — never the API key. const { token, interviewId } = await response.json(); res.json({ token, interviewId }); } catch (err) { console.error('Session creation failed:', err.message); res.status(500).json({ error: 'Could not create session' }); } }); // POST /finish — mark the session complete and fetch the score app.post('/finish', async (req, res) => { const { token, interviewId } = req.body; try { // Fetch the verification score using the session token. // X-Incode-Hardware-Id carries the session token for /0/ endpoints. const scoreRes = await fetch(`${API_URL}/0/omni/get/score`, { method: 'GET', headers: { 'api-version': '1.0', 'x-api-key': API_KEY, 'X-Incode-Hardware-Id': token, }, }); if (!scoreRes.ok) { throw new Error(`Score fetch failed: ${scoreRes.status}`); } const score = await scoreRes.json(); // In production, apply your business rules here. // score.idValidation.overall.status → 'OK', 'WARN', 'FAIL' // score.liveness.overall.status → 'OK', 'WARN', 'FAIL' // score.faceRecognition.overall.status → 'OK', 'WARN', 'FAIL' // score.overall.status → 'OK', 'WARN', 'FAIL', 'MANUAL' res.json({ interviewId, score }); } catch (err) { console.error('Finish failed:', err.message); res.status(500).json({ error: 'Could not retrieve score' }); } }); app.listen(3000, () => console.log('Server running at http://localhost:3000')); - Start the server:
node server.js
Step 2.4: Create the Front-End Page
Create a public/ folder, then create public/index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Incode Quick Start</title>
<!-- Load the Incode Web SDK from CDN -->
<script src="https://sdk.incode.com/sdk/onBoarding-1.85.0.js" defer></script>
<style>
body { font-family: sans-serif; max-width: 600px; margin: 2rem auto; padding: 0 1rem; }
#camera-container { width: 100%; min-height: 300px; }
#result { margin-top: 1.5rem; padding: 1rem; background: #f5f5f5; border-radius: 6px; display: none; }
pre { font-size: 13px; overflow: auto; }
</style>
</head>
<body>
<h1>Identity Verification</h1>
<p id="status">Starting session...</p>
<div id="camera-container"></div>
<div id="result">
<h2>Verification Complete</h2>
<pre id="score-output"></pre>
</div>
<script>
const container = document.getElementById('camera-container');
const statusEl = document.getElementById('status');
const resultEl = document.getElementById('result');
const scoreOutput = document.getElementById('score-output');
let incode = null;
let session = null; // { token, interviewId }
async function init() {
// Step 1: Ask the backend to create a session.
// The API key stays on the server — the frontend only receives the token.
const res = await fetch('/start', { method: 'POST' });
session = await res.json();
// Step 2: Initialize the Web SDK with your API URL and the session token.
// Do NOT pass the API key here.
incode = window.OnBoarding.create({
apiURL: 'https://demo-api.incodesmile.com/0', // note the /0 path
token: session.token,
});
statusEl.textContent = 'Session ready. Starting ID capture...';
captureIdFront();
}
// Step 3: Capture the front of the ID document
function captureIdFront() {
incode.renderCamera('front', container, {
token: session,
numberOfTries: 3,
onSuccess: captureIdBack,
onError: handleError,
});
}
// Step 4: Capture the back of the ID document (skip for passports)
function captureIdBack() {
incode.renderCamera('back', container, {
token: session,
numberOfTries: 3,
onSuccess: processId,
onError: handleError,
});
}
// Step 5: Tell Incode to process the captured ID images
async function processId() {
statusEl.textContent = 'Processing ID...';
container.innerHTML = '<p>Processing your ID — please wait.</p>';
await incode.processId({ token: session.token });
captureSelfie();
}
// Step 6: Capture the selfie
function captureSelfie() {
statusEl.textContent = 'ID processed. Starting selfie capture...';
incode.renderCamera('selfie', container, {
token: session,
numberOfTries: 3,
showTutorial: true,
onSuccess: finishSession,
onError: handleError,
});
}
// Step 7: Send the session token to your backend to mark completion and fetch the score
async function finishSession() {
statusEl.textContent = 'Verification complete. Fetching results...';
container.innerHTML = '';
const res = await fetch('/finish', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(session),
});
const result = await res.json();
// Display the score for this tutorial — in production, apply your business rules
resultEl.style.display = 'block';
scoreOutput.textContent = JSON.stringify(result.score, null, 2);
statusEl.textContent = `Session ${result.interviewId} complete.`;
}
function handleError(err) {
statusEl.textContent = `Error: ${err?.message || 'An error occurred'}`;
console.error(err);
}
// Run on page load
window.addEventListener('DOMContentLoaded', init);
</script>
</body>
</html>
Note
The CDN URL above references SDK version 1.85.0. Always use the latest version — check Web SDK Release Notes for the current version number.
Step 2.5: Run It on Your Phone
The Incode Web SDK requires HTTPS and a real camera. For local development, use a tunneling tool to expose your local server over HTTPS:
# Using ngrok (install from ngrok.com if needed)
ngrok http 3000
Copy the https:// URL ngrok provides and open it on your phone. Go through the verification as you did in Part 1.
When the selfie capture completes, your back end fetches the score and the result appears on screen.
Step 2.6: Read the Score
Your /finish endpoint returns a score object that looks like this:
{
"idValidation": {
"overall": {
"value": "98.0",
"status": "OK"
}
},
"liveness": {
"overall": {
"value": "100.0",
"status": "OK"
}
},
"faceRecognition": {
"overall": {
"value": "97.5",
"status": "OK"
}
},
"overall": {
"status": "OK"
}
}
Use the status field—not the numeric value—to make decisions. The possible status values are:
| Status | Meaning |
|---|---|
OK |
Module passed. |
WARN |
Score is borderline; consider routing to manual review. |
MANUAL |
Session requires a human reviewer. |
FAIL |
Module failed. |
UNKNOWN |
Result could not be determined. |
A typical decision pattern in your back end:
const { overall } = score;
if (overall.status === 'OK') {
// Approve the user and continue your onboarding flow
} else if (overall.status === 'WARN' || overall.status === 'MANUAL') {
// Route to manual review queue
} else {
// Reject and prompt the user to try again or contact support
}
What You Built
In Part 1 you ran a live verification session and saw the result in Dashboard. In Part 2 you built a working integration that:
- Creates a session from your back end using your API key.
- Passes only the session token to the front end.
- Runs ID capture, ID processing, and selfie capture using the Web SDK.
- Retrieves the verification score from your back end after the session completes.
This is the foundation every Incode web integration is built on. The same pattern applies whether you add more modules, switch to webhooks for async results, or move to a mobile SDK.
What's Next
| Goal | Where to go |
|---|---|
| Add consent, geolocation, or eKYC modules | Web SDK Tutorial (Full) |
| Build a React integration | Extended Onboarding: React |
| Receive results asynchronously instead of polling | Webhooks |
| Use a mobile SDK instead | iOS · Android · React Native · Flutter · Xamarin · Cordova · Ionic Capacitor |
| Understand all score fields | Fetch Score Data |