> ## 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.

# Didit iframe 身份验证：嵌入式网页 KYC

> 通过 iframe 在您的网站中嵌入 KYC、KYB、AML 和活体检测。支持 UniLink 无代码或 API 会话。每次完整 KYC 检查 $0.33 起，每月 10 美元免费额度，无合同。



Iframe 集成提示词
        将提示词复制到剪贴板



      
      

\<pre>

\`Embed Didit identity verification into my web page using an iframe.

\## Two Options

\### Option A: UniLink (no backend — fastest setup)
Copy your UniLink URL from Didit Console > Workflows > Copy Link.
It looks like: https://verify.didit.me/u/<BASE64_WORKFLOW_ID>
Embed it directly:

\<iframe
src="https://verify.didit.me/u/YOUR_WORKFLOW_ID_BASE64"
style="width: 100%; height: 700px; border: none; border-radius: 12px;"
allow="camera; microphone; geolocation; clipboard-write; fullscreen; autoplay; encrypted-media; digital-credentials-get"
/>

No backend needed. Results appear in your Didit Console dashboard.

\### Option B: API session (full control)
1\. Backend creates session: POST /v3/session/ → response includes "url"
2\. Frontend embeds that "url" as the iframe src
3\. Listen for postMessage events from the iframe (event.origin === 'https://verify.didit.me', or your white-label domain)
4\. Backend receives the full, signed decision via webhook (status.updated)

\## postMessage contract (key events — full table below)
Every message is an object: { type: "didit:<event>", data: { ... }, timestamp: <ms epoch> }
Completion event: type === "didit:completed", data: { sessionId, status }
Other events: didit:ready { sessionId }, didit:started, didit:step_started { step },
didit:step_completed { step, nextStep }, didit:step_changed { step, previousStep },
didit:status_updated { status }, didit:error { error, step }, didit:cancelled, didit:close_request,
didit:layout { contentHeight, colorScheme: "light" | "dark", dir: "ltr" | "rtl" }
The payload is NESTED under event.data.data (event.data is the envelope).
For your own iframe, add sdk_presentation=embedded with the URL API to receive didit:layout.

\## Iframe size (redesigned flow)
\- Window 1024px and wider: 960px by 660px (at most 90% of the window)
\- Window 541px to 1023px: 500px wide, height = didit:layout contentHeight (700px until the first message, at most 90% of the window height)
\- Window 540px and below: full screen

\## Frontend Code (Option B — React)
function VerificationIframe({ verificationUrl }) {
useEffect(() => {
function handleMessage(event) {
  if (event.origin !== 'https://verify.didit.me') return; // use your white-label domain if configured
  const { type, data } = event.data || {};
  if (type === 'didit:completed') {
    // data.sessionId, data.status: "Approved" | "Declined" | "In Review" // open string — other session statuses possible in edge flows
    // Trust the webhook on your backend for the canonical decision.
  }
}
window.addEventListener('message', handleMessage);
return () => window.removeEventListener('message', handleMessage);
}, []);

return (
\<iframe
  src={verificationUrl}
  style={{ width: '100%', height: '700px', border: 'none', borderRadius: '12px' }}
  allow="camera; microphone; geolocation; clipboard-write; fullscreen; autoplay; encrypted-media; digital-credentials-get"
/>
);
}

\## Required client-side permissions
If you front your site with a reverse proxy (nginx, Cloudflare, etc.) make sure it does not
strip the Permissions-Policy / Feature-Policy headers — camera and microphone access must be
allowed for your origin or the iframe will be unable to start the camera.

\## Required iframe Permissions
allow="camera; microphone; geolocation; clipboard-write; fullscreen; autoplay; encrypted-media; digital-credentials-get"
camera: document and face capture. microphone: optional audio during video capture.
geolocation: the location step. clipboard-write: the copy buttons.
digital-credentials-get: sharing a digital ID from a wallet such as Google Wallet.

\## Backend: Create Session
POST https://verification.didit.me/v3/session/
Headers: { "x-api-key": DIDIT_API_KEY, "Content-Type": "application/json" }
Body: { "workflow_id": DIDIT_WORKFLOW_ID, "vendor_data": userId }
201 response fields (all 10, per OpenAPI):
\{ "session_id", "session_number", "session_token", "url", "vendor_data", "metadata",
"status", "workflow_id", "workflow_version", "callback" }
Use response.url as the iframe src — never build the URL from session_token by hand.

\## Rate Limits
600 session-create requests per minute per API key (falls back to bearer token, then client IP), plus a shared 300 write-requests/minute budget across all endpoints. HTTP 429 with Retry-After when exceeded.

\## Environment Variables
\- DIDIT_API_KEY (backend only)
\- DIDIT_WORKFLOW_ID (backend only)

\## Docs
\- Iframe guide: https://docs.didit.me/integration/web-sdks/incontext-iframe
\- Create Session: https://docs.didit.me/sessions-api/create-session
\- Webhooks: https://docs.didit.me/integration/webhooks`

\</pre>



      
      

粘贴到

使用 iframe 将 Didit 验证流程直接嵌入您的应用中。这样可以提供无缝的体验，无需将用户重定向离开您的网站。## 概述| 功能 | UniLink（无需后端） | API 会话（需要后端） |
| - | - | - |
| 设置时间 | \< 1 分钟 | 5-10 分钟 |
| 需要后端 | ❌ 否 | ✅ 是 |
| 自定义 `vendor_data` | ❌ 否 | ✅ 是 |
| 自定义 `metadata` | ❌ 否 | ✅ 是 |
| 每次会话回调 | ❌ 否 | ✅ 是 |
| 会话跟踪 | ❌ 否 | ✅ 是 |***## UniLink iframe（无需后端）最快的入门方式，只需复制并粘贴您的 UniLink URL。### 所需条件1) 一个 Didit 工作流（在 [Didit 控制台](https://business.didit.me) 中创建）
2) 您的 UniLink URL（在工作流中点击 **复制链接**）### 实现```html theme={null}
<iframe 
  src="https://verify.didit.me/u/YOUR_WORKFLOW_ID_BASE64"
  style="width: 100%; height: 700px; border: none;" 
  allow="camera; microphone; geolocation; clipboard-write; fullscreen; autoplay; encrypted-media; digital-credentials-get"
></iframe>
```> ⚠️ **必填**：活体检测期间访问摄像头必须设置 `allow` 属性。### 主要优势- **不到 1 分钟即可完成设置**，无需后端，无需 API 密钥
- **零配置**，回调 URL 在工作流设置中配置
- **适合 MVP**，可立即开始***## API 会话 iframe（需要后端）适用于需要按会话进行自定义的高级集成。### 适用场景- 为每次会话传入自定义 `vendor_data` 或 `metadata`
- 为每次会话设置不同的回调 URL
- 在验证开始前在服务端跟踪会话
- 将会话与您的用户 ID 关联### 实现**步骤 1：创建会话（后端）**会话创建响应使用名为 **`url`** 的字段，请将其用作 iframe 的 `src`。```javascript theme={null}
// 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_API_KEY,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      workflow_id: process.env.DIDIT_WORKFLOW_ID,
      vendor_data: userId,
      callback: 'https://yourapp.com/verification-callback',
      metadata: { source: 'web-app', timestamp: Date.now() },
    }),
  });

  if (!response.ok) {
    return res.status(response.status).send(await response.text());
  }

  // 201 per OpenAPI: { session_id, session_number, session_token, url, vendor_data,
  //                    metadata, status, workflow_id, workflow_version, callback }
  const session = await response.json();
  res.json({ sessionId: session.session_id, verificationUrl: session.url });
});
```**步骤 2：在 iframe 中嵌入（前端）**```html theme={null}
<iframe 
  id="didit-verification"
  src="" <!-- Set dynamically from API response -->
  style="width: 100%; height: 650px; border: none;" 
  allow="camera; microphone; geolocation; clipboard-write; fullscreen; autoplay; encrypted-media; digital-credentials-get"
></iframe>

<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();
    document.getElementById('didit-verification').src = verificationUrl;
  }
</script>
```***## 监听事件（postMessage）验证页面会向父窗口发送事件。每条消息都具有以下结构：```typescript theme={null}
{
  type: 'didit:<event>',   // e.g. 'didit:completed'
  data: { /* payload */ }, // event-specific; may be undefined
  timestamp: 1718000000000 // ms epoch
}
```payload 是**嵌套**的，请读取 `event.data.data.sessionId`，而不是 `event.data.sessionId`：```javascript theme={null}
window.addEventListener('message', (event) => {
  // Use your white-label domain here if you have one configured
  if (event.origin !== 'https://verify.didit.me') return;

  const { type, data } = event.data || {};

  if (type === 'didit:ready') {
    console.log('Session ID:', data.sessionId); // available as soon as the page loads
  }
  if (type === 'didit:completed') {
    console.log('Done:', data.sessionId, data.status); // e.g. "Approved" | "Declined" | "In Review"
    // UI hint only — the canonical decision arrives on your backend via webhook
  }
});
```主要事件：`didit:ready`（`{ sessionId }`）、`didit:started`、`didit:step_started` / `didit:step_completed` / `didit:step_changed`（`{ step, ... }`）、`didit:status_updated`（`{ status }`）、`didit:completed`（`{ sessionId, status }`）、`didit:cancelled`、`didit:error`（`{ error, step? }`）、`didit:close_request`，以及 `didit:layout`（`{ contentHeight, colorScheme, dir }`，参见[下文](#根据-diditlayout-设置-iframe-尺寸)）。[JavaScript SDK 事件参考](https://docs.didit.me/zh/integration/web-sdks/javascript-sdk.md#事件参考)列出了可作为类型化回调使用的验证事件。从 0.5.0 版本开始，SDK 会在内部处理布局消息，而不会将其转发给 `onEvent`。### 根据 `didit:layout` 设置 iframe 尺寸验证页面会通过 `didit:layout` 消息告知所需的空间。页面加载时会发送一条消息，之后每当其内容高度、主题或文本方向发生变化时，都会再次发送：```typescript theme={null}
{
  type: 'didit:layout',
  data: {
    contentHeight: 612,    // CSS px
    colorScheme: 'light',  // 'light' | 'dark'
    dir: 'ltr'             // 'ltr' | 'rtl'
  },
  timestamp: 1718000000000
}
```| 字段 | 类型 | 说明 |
| - | - | - |
| `contentHeight` | `number` | 页面内容的自然高度（CSS 像素），包括顶部栏 |
| `colorScheme` | `'light' \| 'dark'` | 页面显示的主题。使用白标颜色时，由您的背景色决定主题，而不是设备设置 |
| `dir` | `'ltr' \| 'rtl'` | 页面语言的文本方向 |> [!NOTE]
>
> 要在您自己的 iframe 中接收 `didit:layout`，请在其验证 URL 中添加 `sdk_presentation=embedded`。从 0.5.0 版本开始，[JavaScript SDK](https://docs.didit.me/zh/integration/web-sdks/javascript-sdk.md) 会自动为您设置展示方式。如果没有展示参数，页面将使用独立布局，并且不会发送布局消息。本宿主遵循[推荐尺寸](#iframe-尺寸)：宽度 1024px 及以上使用固定卡片，540px 及以下全屏显示，两者之间使用宽 500px 的 iframe，其高度取自页面报告的值：```html theme={null}
<iframe
  id="didit-verification"
  class="didit-iframe"
  title="Didit verification"
  allow="camera; microphone; geolocation; clipboard-write; fullscreen; autoplay; encrypted-media; digital-credentials-get"
></iframe>

<style>
  /* 541px to 1023px wide: 500px wide and as tall as the content */
  .didit-iframe {
    display: block;
    width: 500px;
    max-width: 100%;
    height: var(--didit-content-height, 700px); /* 700px until the first didit:layout */
    max-height: 90vh;
    max-height: 90dvh;
    margin: 0 auto;
    border: none;
    border-radius: 16px;
  }

  /* 1024px and wider: the computer card */
  @media (min-width: 1024px) {
    .didit-iframe {
      width: 960px;
      max-width: 90vw;
      height: 660px;
    }
  }

  /* 540px and below: full screen */
  @media (max-width: 540px) {
    .didit-iframe {
      position: fixed;
      inset: 0;
      width: 100%;
      height: 100vh;
      height: 100dvh;
      max-height: none;
      border-radius: 0;
    }
  }
</style>

<script>
  const DIDIT_ORIGIN = 'https://verify.didit.me'; // or your white-label domain
  const iframe = document.getElementById('didit-verification');

  // verificationUrl: the session `url` from your backend, or your UniLink
  const src = new URL(verificationUrl);
  src.searchParams.set('sdk_presentation', 'embedded');
  window.addEventListener('message', (event) => {
    if (event.origin !== DIDIT_ORIGIN || event.source !== iframe.contentWindow) return;
    const { type, data } = event.data || {};
    if (type !== 'didit:layout') return;
    const height = data?.contentHeight;
    if (typeof height !== 'number' || !Number.isFinite(height) || height <= 0) return;

    // Only the 541px to 1023px size reads it; the other two sizes are fixed
    iframe.style.setProperty('--didit-content-height', `${height}px`);
  });
  iframe.src = src.toString();
</script>
```在 541px 至 1023px 之间，此示例在收到布局消息前使用 700px 的初始高度，并且最高不超过可见窗口高度的 90%。电脑和手机尺寸会立即生效。在手机上 iframe 会覆盖整个窗口，因此请在宿主页面中提供退出验证的方式。请使用 `colorScheme` 和 `dir`，使您在 iframe 周围绘制的控件与页面的主题和文本方向保持一致。如果用户的网络连接中断，页面会显示“无网络连接”屏幕，网络恢复后该屏幕会自动关闭。如果用户在此屏幕上选择**退出验证**，页面会先发送 `didit:error`（`error: "network_error"`），然后发送 `didit:cancelled`：收到 `didit:cancelled` 时请关闭 iframe。***## 模态框实现如需在页面上叠加显示一个精致的模态框体验：### HTML/CSS/JS```html theme={null}
<!DOCTYPE html>
<html>
<head>
  <style>
    .didit-modal-overlay {
      display: none;
      position: fixed;
      inset: 0;
      background: rgba(0, 0, 0, 0.6);
      z-index: 9999;
      backdrop-filter: blur(4px);
    }
    
    .didit-modal-container {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      width: 90%;
      max-width: 480px;
      height: 85vh;
      max-height: 750px;
      background: white;
      border-radius: 16px;
      overflow: hidden;
      box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
    }
    
    .didit-modal-close {
      position: absolute;
      top: 12px;
      right: 12px;
      z-index: 10;
      width: 32px;
      height: 32px;
      border: none;
      background: rgba(0, 0, 0, 0.1);
      border-radius: 50%;
      cursor: pointer;
      font-size: 18px;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    
    .didit-modal-close:hover {
      background: rgba(0, 0, 0, 0.2);
    }
    
    .didit-iframe {
      width: 100%;
      height: 100%;
      border: none;
    }
  </style>
</head>
<body>
  <button onclick="openVerification()">Verify Identity</button>

  <div id="didit-modal" class="didit-modal-overlay">
    <div class="didit-modal-container">
      <button class="didit-modal-close" onclick="closeVerification()">✕</button>
      <iframe 
        id="didit-iframe"
        class="didit-iframe"
        allow="camera; microphone; geolocation; clipboard-write; fullscreen; autoplay; encrypted-media; digital-credentials-get"
      ></iframe>
    </div>
  </div>

  <script>
    const UNILINK_URL = 'https://verify.didit.me/u/YOUR_WORKFLOW_ID_BASE64';
    
    function openVerification() {
      document.getElementById('didit-iframe').src = UNILINK_URL;
      document.getElementById('didit-modal').style.display = 'block';
      document.body.style.overflow = 'hidden';
    }
    
    function closeVerification() {
      document.getElementById('didit-iframe').src = '';
      document.getElementById('didit-modal').style.display = 'none';
      document.body.style.overflow = '';
    }
    
    // Close on escape key
    document.addEventListener('keydown', (e) => {
      if (e.key === 'Escape') closeVerification();
    });
    
    // Close on overlay click
    document.getElementById('didit-modal').addEventListener('click', (e) => {
      if (e.target.id === 'didit-modal') closeVerification();
    });
  </script>
</body>
</html>
```***## React 组件用于模态框验证的可复用 React 组件：```tsx theme={null}
import { useState, useEffect } from 'react';

interface DiditInContextProps {
  /**
   * Either the `url` returned by POST /v3/session/ (API session)
   * or your UniLink URL copied from the Console (Workflows → Copy Link).
   * Don't derive the UniLink yourself — the path segment is a 22-character
   * base64url encoding of the workflow UUID's raw bytes, not btoa(workflowId).
   */
  verificationUrl: string;
  isOpen: boolean;
  onClose: () => void;
  onComplete?: (sessionId: string, status: string) => void;
}

export function DiditInContext({ 
  verificationUrl, 
  isOpen, 
  onClose,
  onComplete 
}: DiditInContextProps) {
  const [iframeSrc, setIframeSrc] = useState<string>('');

  useEffect(() => {
    if (isOpen) {
      setIframeSrc(verificationUrl);
      document.body.style.overflow = 'hidden';
    } else {
      setIframeSrc('');
      document.body.style.overflow = '';
    }
  }, [isOpen, verificationUrl]);

  // Listen for postMessage from iframe
  // Messages look like: { type: 'didit:<event>', data: {...}, timestamp }
  useEffect(() => {
    const handleMessage = (event: MessageEvent) => {
      // Use your white-label domain here if you have one configured
      if (event.origin !== 'https://verify.didit.me') return;

      if (event.data?.type === 'didit:completed' && onComplete) {
        onComplete(event.data.data?.sessionId, event.data.data?.status);
        onClose();
      }
    };

    window.addEventListener('message', handleMessage);
    return () => window.removeEventListener('message', handleMessage);
  }, [onComplete, onClose]);

  // Handle escape key
  useEffect(() => {
    const handleEscape = (e: KeyboardEvent) => {
      if (e.key === 'Escape' && isOpen) onClose();
    };
    
    document.addEventListener('keydown', handleEscape);
    return () => document.removeEventListener('keydown', handleEscape);
  }, [isOpen, onClose]);

  if (!isOpen) return null;

  return (
    <div 
      className="fixed inset-0 bg-black/60 backdrop-blur-sm z-50 flex items-center justify-center"
      onClick={(e) => e.target === e.currentTarget && onClose()}
    >
      <div className="relative w-[90%] max-w-[480px] h-[85vh] max-h-[750px] bg-white rounded-2xl overflow-hidden shadow-2xl">
        <button 
          onClick={onClose}
          className="absolute top-3 right-3 z-10 w-8 h-8 rounded-full bg-black/10 hover:bg-black/20 flex items-center justify-center"
          aria-label="Close"
        >
          ✕
        </button>
        <iframe 
          src={iframeSrc}
          className="w-full h-full border-0"
          allow="camera; microphone; geolocation; clipboard-write; fullscreen; autoplay; encrypted-media; digital-credentials-get"
          title="Didit Verification"
        />
      </div>
    </div>
  );
}
```### 用法```tsx theme={null}
import { useState } from 'react';
import { DiditInContext } from './DiditInContext';

function App() {
  const [isVerificationOpen, setIsVerificationOpen] = useState(false);
  
  return (
    <>
      <button onClick={() => setIsVerificationOpen(true)}>
        Verify Identity
      </button>
      
      <DiditInContext
        verificationUrl="https://verify.didit.me/u/YOUR_WORKFLOW_ID_BASE64" // UniLink from Console, or the API session `url`
        isOpen={isVerificationOpen}
        onClose={() => setIsVerificationOpen(false)}
        onComplete={(sessionId, status) => {
          console.log(`Verification ${status}: ${sessionId}`);
          if (status === 'Approved') {
            // Navigate to success page
          }
        }}
      />
    </>
  );
}
```***## Vue 组件```vue theme={null}
<template>
  <Teleport to="body">
    <div 
      v-if="isOpen"
      class="fixed inset-0 bg-black/60 backdrop-blur-sm z-50 flex items-center justify-center"
      @click.self="$emit('close')"
    >
      <div class="relative w-[90%] max-w-[480px] h-[85vh] max-h-[750px] bg-white rounded-2xl overflow-hidden shadow-2xl">
        <button 
          @click="$emit('close')"
          class="absolute top-3 right-3 z-10 w-8 h-8 rounded-full bg-black/10 hover:bg-black/20 flex items-center justify-center"
        >
          ✕
        </button>
        <iframe 
          :src="iframeSrc"
          class="w-full h-full border-0"
          allow="camera; microphone; geolocation; clipboard-write; fullscreen; autoplay; encrypted-media; digital-credentials-get"
        />
      </div>
    </div>
  </Teleport>
</template>

<script setup lang="ts">
import { computed, watch, onMounted, onUnmounted } from 'vue';

const props = defineProps<{
  isOpen: boolean;
  // The `url` from POST /v3/session/, or your UniLink URL copied from the
  // Console (Workflows → Copy Link). Don't derive the UniLink with btoa() —
  // its path segment is base64url of the workflow UUID's raw bytes.
  verificationUrl: string;
}>();

const emit = defineEmits<{
  close: [];
  complete: [sessionId: string, status: string];
}>();

const iframeSrc = computed(() => (props.isOpen ? props.verificationUrl : ''));

// Handle escape key
const handleEscape = (e: KeyboardEvent) => {
  if (e.key === 'Escape' && props.isOpen) emit('close');
};

// Handle postMessage — messages look like { type: 'didit:<event>', data: {...}, timestamp }
const handleMessage = (event: MessageEvent) => {
  // Use your white-label domain here if you have one configured
  if (event.origin !== 'https://verify.didit.me') return;
  if (event.data?.type === 'didit:completed') {
    emit('complete', event.data.data?.sessionId, event.data.data?.status);
  }
};

onMounted(() => {
  document.addEventListener('keydown', handleEscape);
  window.addEventListener('message', handleMessage);
});

onUnmounted(() => {
  document.removeEventListener('keydown', handleEscape);
  window.removeEventListener('message', handleMessage);
});

// Lock body scroll when open
watch(() => props.isOpen, (isOpen) => {
  document.body.style.overflow = isOpen ? 'hidden' : '';
});
</script>
```***## 配置### 所需权限使用以下完整权限列表，以支持采集、位置、复制和媒体兼容性：```html theme={null}
allow="camera; microphone; geolocation; clipboard-write; fullscreen; autoplay; encrypted-media; digital-credentials-get"
```| 权限 | 用途及未授予时的情况 |
| - | - |
| `camera` | 用于证件扫描和人脸采集。未授予时，摄像头无法启动，用户会看到摄像头访问指引 |
| `microphone` | 证件和人脸视频采集期间的可选音频。未授予时，采集继续进行，但不录制音频 |
| `geolocation` | 位置步骤读取设备的位置。未授予时，即使用户已在浏览器中允许位置访问，仍会看到**位置访问已关闭** |
| `clipboard-write` | 复制会话引用或验证链接，包括应用内浏览器页面上的复制。未授予时，复制操作可能失败，用户必须手动复制可见文本或浏览器地址 |
| `fullscreen` | 允许媒体控件请求全屏。未授予时，这些控件只能停留在 iframe 内 |
| `autoplay` | 允许说明视频和摄像头预览根据浏览器规则自动播放。未授予时，播放可能需要等待用户操作 |
| `encrypted-media` | 为受保护媒体的兼容性而保留。当前的采集步骤不需要此权限；未授予时，受保护媒体的播放会被阻止 |
| `digital-credentials-get` | 通过浏览器的 Digital Credentials API，从 Google Wallet 等钱包分享数字身份证件。未授予时，浏览器会拒绝 iframe 内的钱包请求，用户无法在此处从钱包分享身份证件 |`allow` 属性用于委派权限；它不会覆盖用户的选择，也不会覆盖宿主页面中更严格的 `Permissions-Policy` 响应头。### iframe 尺寸验证流程会根据其 iframe 的尺寸自动布局。请根据显示它的窗口来设置 iframe 尺寸：| 窗口宽度 | 推荐的 iframe 尺寸 |
| - | - |
| 1024px 及以上（电脑） | 960px × 660px，且不超过窗口宽度和高度的 90%。每个步骤都保持此尺寸 |
| 541px 至 1023px | 宽 500px，高度与内容一致：从 [`didit:layout` 消息](#根据-diditlayout-设置-iframe-尺寸)的 `contentHeight` 获取高度，且不超过窗口高度的 90% |
| 540px 及以下（手机） | 全屏：占满窗口的全部宽度和全部可见高度，且不设圆角 |对于中间宽度范围，在收到第一条 `didit:layout` 消息之前，从 500px × 700px 开始，高度上限相同。[`didit:layout` 示例](#根据-diditlayout-设置-iframe-尺寸)展示了全部三种尺寸，包括在收到任何消息之前的电脑和手机尺寸。### 内容安全策略 (CSP)如果您使用 CSP，请将 Didit 添加到您的 `frame-src` 指令中：```
Content-Security-Policy: frame-src https://verify.didit.me;
```***## 跨设备验证InContext iframe 自动支持跨设备验证：1) 用户在桌面端开始验证
2) 如果摄像头不可用，会显示二维码
3) 用户使用手机扫描二维码
4) 用户在手机上完成验证
5) 桌面端 iframe 自动更新结果这一过程自动完成，无需额外配置。***## 故障排除### 摄像头无法工作1) 确保 iframe 包含完整的[权限列表](#所需权限)
2) 检查您的站点是否通过 HTTPS 提供服务
3) 确认用户已为您的域名授予摄像头权限
4) 如果 iframe 中的摄像头访问失败，请尝试[重定向](https://docs.didit.me/zh/integration/web-sdks/web-redirect.md)方式### iframe 无法加载1) 检查是否存在内容安全策略（CSP）问题
2) 将 `https://verify.didit.me` 添加到您的 `frame-src` 指令中
3) 检查浏览器控制台中的错误### 未收到 postMessage1) 确认您监听的来源正确（`https://verify.didit.me`，或您的白标域名）
2) 确保在打开 iframe 之前已添加事件监听器
3) 检查事件名称和数据结构：类型带有前缀（使用 `didit:completed`，而不是 `verification_complete`），payload 嵌套在 `event.data.data` 下***## 示例仓库> [card] [GitHub 仓库](https://github.com/didit-protocol/iframe-example)
>
> 在 GitHub 上查看源代码和示例***


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.