Skip to main content
The Redirect method sends users to a Didit-hosted page for verification, then returns them to your app via a callback URL.
FeatureDescription
Setup Time5 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
ParameterDescription
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:
  1. User clicks “Verify” on desktop
  2. User is redirected to verification page
  3. If needed, user can scan QR code to continue on mobile
  4. After completion, both devices receive the result
  5. User is redirected to your callback URL

Troubleshooting

Callback Not Received

  1. Verify the callback URL is correctly set when creating the session
  2. Ensure your callback URL is accessible from the internet
  3. Check that the URL doesn’t have typos or encoding issues

Status Always “Declined”

  1. Check your workflow settings in the Didit Console
  2. Verify the test documents you’re using are valid
  3. Review the session details via API for specific decline reasons

Redirect Loop

  1. Ensure your callback handler doesn’t redirect back to verification
  2. Check for caching issues on your callback page
  3. Clear browser cache and try again

Example Repository

GitHub Repository

View source code and examples on GitHub