Documentation Index Fetch the complete documentation index at: https://docs.didit.me/llms.txt
Use this file to discover all available pages before exploring further.
The Redirect method sends users to a Didit-hosted page for verification, then returns them to your app via a callback URL.
Feature Description Setup Time 5 minutes Backend Required ✅ Yes (to create sessions) Stays on Your Domain ❌ No (redirects to verify.didit.me or your whitelabel custom domain) Cross-Device Support ✅ Yes Browser Compatibility ✅ All browsers
When to Use Redirect
Cross-device verification : Start on desktop, complete on mobile
Maximum compatibility : Works in all browsers, including older ones
Simple integration : No iframe configuration needed
Camera issues : When iframe camera access is problematic
Implementation
Step 1: Create a Session (Backend)
// Node.js / Express
app . post ( '/api/create-verification' , async ( req , res ) => {
const { userId } = req . body ;
const response = await fetch ( 'https://verification.didit.me/v3/session/' , {
method: 'POST' ,
headers: {
'x-api-key' : process . env . DIDIT_ACCESS_TOKEN ,
'Content-Type' : 'application/json'
},
body: JSON . stringify ({
workflow_id: process . env . DIDIT_WORKFLOW_ID ,
vendor_data: userId ,
callback: 'https://yourapp.com/verification-complete'
})
});
const data = await response . json ();
res . json ({ verificationUrl: data . verification_url });
});
Step 2: Redirect the User (Frontend)
HTML:
< button onclick = " startVerification ()" > Verify Identity </ button >
< script >
async function startVerification () {
const response = await fetch ( '/api/create-verification' , {
method: 'POST' ,
headers: { 'Content-Type' : 'application/json' },
body: JSON . stringify ({ userId: 'user-123' })
});
const { verificationUrl } = await response . json ();
window . location . href = verificationUrl ;
}
</ script >
React:
function VerifyButton () {
const [ loading , setLoading ] = useState ( false );
const startVerification = async () => {
setLoading ( true );
const response = await fetch ( '/api/create-verification' , {
method: 'POST' ,
headers: { 'Content-Type' : 'application/json' },
body: JSON . stringify ({ userId: 'user-123' })
});
const { verificationUrl } = await response . json ();
window . location . assign ( verificationUrl );
};
return (
< button onClick = { startVerification } disabled = { loading } >
{ loading ? 'Loading...' : 'Verify Identity' }
</ button >
);
}
Vue:
< template >
< button @ click = " startVerification " : disabled = " loading " >
{{ loading ? 'Loading...' : 'Verify Identity' }}
</ button >
</ template >
< script setup >
import { ref } from 'vue' ;
const loading = ref ( false );
async function startVerification () {
loading . value = true ;
const response = await fetch ( '/api/create-verification' , {
method: 'POST' ,
headers: { 'Content-Type' : 'application/json' },
body: JSON . stringify ({ userId: 'user-123' })
});
const { verificationUrl } = await response . json ();
window . location . href = verificationUrl ;
}
</ script >
Handling the Callback
When verification completes, Didit redirects to your callback URL with query parameters:
https://yourapp.com/verification-complete?verificationSessionId=abc123&status=Approved
Parameter Description verificationSessionIdUnique session identifier statusApproved, Declined, or In Review
Next.js Example
// pages/verification-complete.tsx
import { useRouter } from 'next/router' ;
import { useEffect , useState } from 'react' ;
export default function VerificationComplete () {
const router = useRouter ();
const { verificationSessionId , status } = router . query ;
const [ message , setMessage ] = useState ( 'Processing...' );
useEffect (() => {
if ( ! router . isReady ) return ;
async function handleResult () {
// Optionally verify the result with your backend
await fetch ( '/api/verify-session' , {
method: 'POST' ,
headers: { 'Content-Type' : 'application/json' },
body: JSON . stringify ({
sessionId: verificationSessionId ,
status
})
});
// Redirect based on status
switch ( status ) {
case 'Approved' :
setMessage ( 'Verification successful! Redirecting...' );
setTimeout (() => router . push ( '/dashboard' ), 2000 );
break ;
case 'Declined' :
setMessage ( 'Verification was not successful.' );
setTimeout (() => router . push ( '/verification-failed' ), 2000 );
break ;
case 'In Review' :
setMessage ( 'Your verification is under review.' );
setTimeout (() => router . push ( '/verification-pending' ), 2000 );
break ;
default :
setMessage ( 'Unknown status. Please contact support.' );
}
}
handleResult ();
}, [ router . isReady , verificationSessionId , status ]);
return (
< div className = "flex flex-col items-center justify-center min-h-screen" >
< div className = "animate-spin w-8 h-8 border-4 border-blue-500 border-t-transparent rounded-full mb-4" />
< p className = "text-lg" > { message } </ p >
</ div >
);
}
Express.js Example
// routes/verification.js
app . get ( '/verification-complete' , async ( req , res ) => {
const { verificationSessionId , status } = req . query ;
// Optionally verify with Didit API
// const session = await diditApi.getSession(verificationSessionId);
// Update your database
await db . users . update ({
where: { verificationSessionId },
data: { verificationStatus: status }
});
// Redirect based on status
switch ( status ) {
case 'Approved' :
res . redirect ( '/dashboard?verified=true' );
break ;
case 'Declined' :
res . redirect ( '/verification-failed' );
break ;
case 'In Review' :
res . redirect ( '/verification-pending' );
break ;
default :
res . redirect ( '/error' );
}
});
Vue Router Example
// router/index.ts
{
path : '/verification-complete' ,
component : () => import ( '@/views/VerificationComplete.vue' ),
beforeEnter : async ( to , from , next ) => {
const { verificationSessionId , status } = to . query ;
// Store result and redirect
await store . dispatch ( 'verification/handleResult' , {
sessionId: verificationSessionId ,
status
});
if ( status === 'Approved' ) {
next ( '/dashboard' );
} else if ( status === 'Declined' ) {
next ( '/verification-failed' );
} else {
next ( '/verification-pending' );
}
}
}
Open in New Tab
If you prefer to keep your app open while the user verifies:
// Open in new tab
window . open ( verificationUrl , '_blank' );
// Poll for completion or use webhooks
When using new tabs, combine with webhooks to know when verification completes.
Security Best Practices
Verify the Callback
Always verify the callback data with your backend:
// Backend: Verify the session status
app . get ( '/verification-complete' , async ( req , res ) => {
const { verificationSessionId , status } = req . query ;
// Don't trust the status parameter blindly!
// Verify with Didit API
const response = await fetch (
`https://verification.didit.me/v3/sessions/ ${ verificationSessionId } /` ,
{
headers: {
'x-api-key' : process . env . DIDIT_ACCESS_TOKEN
}
}
);
const session = await response . json ();
// Use the verified status from the API
if ( session . status === 'Approved' ) {
// Grant access
}
});
Use Webhooks
For the most reliable integration, use webhooks to receive verification results directly to your backend, regardless of how the user’s browser behaves.
Cross-Device Flow
The redirect method naturally supports cross-device verification:
User clicks “Verify” on desktop
User is redirected to verification page
If needed, user can scan QR code to continue on mobile
After completion, both devices receive the result
User is redirected to your callback URL
Troubleshooting
Callback Not Received
Verify the callback URL is correctly set when creating the session
Ensure your callback URL is accessible from the internet
Check that the URL doesn’t have typos or encoding issues
Status Always “Declined”
Check your workflow settings in the Didit Console
Verify the test documents you’re using are valid
Review the session details via API for specific decline reasons
Redirect Loop
Ensure your callback handler doesn’t redirect back to verification
Check for caching issues on your callback page
Clear browser cache and try again
Example Repository
GitHub Repository View source code and examples on GitHub