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

# KYC عبر WebView: التحقق من الهوية على الجوال

> من Didit: التحقق من الهوية عبر WebView لـ iOS وAndroid وReact Native وFlutter، كبديل للـ SDK الأصلي. من $0.33 لكل فحص KYC كامل، و$10 مجانًا شهريًا.



دليل تكامل WebView
        نسخ الموجّه إلى الحافظة



      
      

\<pre>

\`Integrate Didit identity verification into my mobile app using a WebView.

\## IMPORTANT: Prefer Native SDKs
Native SDKs exist for every major mobile platform: iOS, Android, React Native, and Flutter.
They provide better UX, NFC passport/ID reading, optimized camera, and biometric integration.
Only use a WebView if you are on a platform with no native SDK (e.g., Xamarin, Cordova).
\- iOS native SDK: https://docs.didit.me/integration/native-sdks/ios-sdk
\- Android native SDK: https://docs.didit.me/integration/native-sdks/android-sdk
\- React Native SDK: https://docs.didit.me/integration/native-sdks/react-native-sdk
\- Flutter SDK: https://docs.didit.me/integration/native-sdks/flutter-sdk

\## Architecture
1\. Backend creates a session via POST /v3/session/ → response includes "url"
2\. App loads response.url in a WebView
3\. User completes verification inside the WebView
4\. WebView navigates to your callback URL when done — app intercepts this
5\. Backend receives the full, signed decision via webhook (status.updated)

\## React Native (Expo / CLI)
Install: npx expo install react-native-webview

import { WebView } from 'react-native-webview';

function VerificationScreen({ verificationUrl, callbackUrl, onDone }) {
const handleNavigationChange = (navState) => {
if (navState.url.startsWith(callbackUrl)) {
  const u = new URL(navState.url);
  onDone({
    sessionId: u.searchParams.get('verificationSessionId'),
    status:    u.searchParams.get('status'), // "Approved" | "Declined" | "In Review"
  });
}
};

return (
\<WebView
  source={{ uri: verificationUrl }}
  onNavigationStateChange={handleNavigationChange}
  javaScriptEnabled
  domStorageEnabled
  mediaPlaybackRequiresUserAction={false}
  allowsInlineMediaPlayback
  mediaCapturePermissionGrantType="grant"
/>
);
}

\## Flutter
Install: flutter pub add webview_flutter webview_flutter_android webview_flutter_wkwebview

controller = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
..setNavigationDelegate(NavigationDelegate(
onNavigationRequest: (request) {
  if (request.url.startsWith(callbackUrl)) {
    final uri = Uri.parse(request.url);
    Navigator.pop(context, {
      'sessionId': uri.queryParameters['verificationSessionId'],
      'status':    uri.queryParameters['status'],
    });
    return NavigationDecision.prevent;
  }
  return NavigationDecision.navigate;
},
))
..loadRequest(Uri.parse(verificationUrl));

\## 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,
"callback": "https://myapp.com/verification-done", // or a custom scheme like myapp://done
"callback_method": "both",
"vendor_data": "user-id"
}
201 response (all 10 fields, per OpenAPI): { session_id, session_number, session_token, url,
vendor_data, metadata, status, workflow_id, workflow_version, callback }
The url embeds the 12-char session_token, e.g. https://verify.didit.me/session/3FaJ9wLqX2Mz
Load response.url in the WebView — never build the URL from session_token by hand.

\## Important WebView Settings
\- Enable JavaScript and DOM storage
\- Grant camera/microphone permissions automatically
\- Allow inline media playback (no fullscreen takeover on iOS)
\- Set a generic mobile user agent string
\- Intercept navigation to your callback URL to detect completion

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

\## Docs
\- WebView guide: https://docs.didit.me/integration/web-sdks/webview-in-ios-android
\- iOS SDK: https://docs.didit.me/integration/native-sdks/ios-sdk
\- Android SDK: https://docs.didit.me/integration/native-sdks/android-sdk
\- Webhooks: https://docs.didit.me/integration/webhooks`

\</pre>



      
      

الصق في

يشرح هذا الدليل كيفية تضمين **تدفق التحقق عبر الويب من Didit** داخل مكوّن **WebView** في تطبيق الهاتف المحمول. وهو **ليس مثل** حزم SDK الأصلية لنظامي iOS وAndroid ولإطاري React Native وFlutter، بل هو خيار احتياطي للمنصات التي لا يمكنها استخدام حزمة SDK أصلية.> [!WARNING]
>
> ### فضّل دائمًا حزم SDK الأصلية
>
> تتوفر حزم SDK الأصلية لنظامي **iOS** و**Android** ولإطاري **React Native** و**Flutter**. وهي توفر أداءً أفضل بكثير، ومعالجة أفضل للكاميرا، وقراءة لجواز السفر أو الهوية عبر NFC، وتكاملًا مع المصادقة البيومترية، وتجربة مستخدم أفضل. **استخدم WebView فقط إذا لم تتوفر حزمة SDK أصلية لمنصتك.**
>
> > [card] [حزمة iOS SDK](https://docs.didit.me/ar/integration/native-sdks/ios-sdk.md)
> >
> > حزمة Swift الأصلية لنظام iOS 13+
>
> > [card] [حزمة Android SDK](https://docs.didit.me/ar/integration/native-sdks/android-sdk.md)
> >
> > حزمة Kotlin الأصلية لنظام Android 6.0+
>
> > [card] [حزمة React Native SDK](https://docs.didit.me/ar/integration/native-sdks/react-native-sdk.md)
> >
> > واجهة برمجة تطبيقات TypeScript متعددة المنصات. متوافقة مع Expo.
>
> > [card] [حزمة Flutter SDK](https://docs.didit.me/ar/integration/native-sdks/flutter-sdk.md)
> >
> > واجهة برمجة تطبيقات Dart متعددة المنصات. حزمة pub.dev.| المنصة | التكامل المفضل | WebView |
| - | - | - |
| iOS | [حزمة iOS الأصلية](https://docs.didit.me/ar/integration/native-sdks/ios-sdk.md): **استخدمها** | غير موصى به |
| Android | [حزمة Android الأصلية](https://docs.didit.me/ar/integration/native-sdks/android-sdk.md): **استخدمها** | غير موصى به |
| React Native | [حزمة React Native](https://docs.didit.me/ar/integration/native-sdks/react-native-sdk.md): **استخدمها** | غير موصى به |
| Flutter | [حزمة Flutter](https://docs.didit.me/ar/integration/native-sdks/flutter-sdk.md): **استخدمها** | غير موصى به |
| منصات أخرى | غير متاح | استخدم WebView كخيار احتياطي |***## متى تستخدم WebViewاستخدم تكامل WebView **فقط** في الحالات التالية:- إذا كنت تبني على منصة لا توجد لها حزمة SDK أصلية (مثل Xamarin أو Cordova أو أطر عمل أخرى أقل انتشارًا)
- إذا كنت تحتاج إلى نموذج أولي سريع أو إثبات مفهوم قبل دمج حزمة SDK الأصلية
- إذا كنت تنتقل من الويب وتريد جسرًا مؤقتًا إلى تكامل أصلي***## كيف يعمل**1. إنشاء جلسة**يستدعي الخادم الخلفي [واجهة برمجة التطبيقات لإنشاء جلسة](https://docs.didit.me/ar/sessions-api/create-session.md) ويتلقى رابطًا مستضافًا في الحقل `url`.**2. الفتح في WebView**يحمّل تطبيقك العنوان `url` في مكوّن WebView.**3. يُكمل المستخدم التحقق**ينتقل المستخدم عبر تدفق التحقق داخل WebView.**4. اعتراض رد الاستدعاء**عند الانتهاء، تنتقل WebView إلى رابط الاستدعاء الخاص بك. يعترض تطبيقك هذا الانتقال ويستخرج النتيجة.**5. الحصول على النتائج الكاملة عبر webhook**يتلقى خادمك الخلفي بيانات القرار الكاملة عبر [webhook](https://docs.didit.me/ar/integration/webhooks.md).***## إنشاء جلسةقبل فتح تدفق التحقق، أنشئ جلسة من خادمك الخلفي:```bash theme={null}
curl -X POST https://verification.didit.me/v3/session/ \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "workflow_id": "your-workflow-id",
    "vendor_data": "user-123",
    "callback": "https://yourapp.com/callback"
  }'
```الاستجابة (`201`، إذ يتضمن الحقل `url` الرمز `session_token` المكوّن من 12 حرفًا، وليس `session_id`):```json theme={null}
{
  "session_id": "11111111-2222-3333-4444-555555555555",
  "session_number": 43762,
  "session_token": "3FaJ9wLqX2Mz",
  "url": "https://verify.didit.me/session/3FaJ9wLqX2Mz",
  "vendor_data": "user-123",
  "metadata": null,
  "status": "Not Started",
  "workflow_id": "11111111-2222-3333-4444-555555555555",
  "workflow_version": 3,
  "callback": "https://yourapp.com/callback"
}
```حمّل الحقل `url` في WebView، ولا تبنِه يدويًا من `session_token` أبدًا.***## React Nativeثبّت حزمة WebView:```bash theme={null}
npm install react-native-webview
# or with Expo
npx expo install react-native-webview
```### التنفيذ```javascript theme={null}
import React from 'react';
import { WebView } from 'react-native-webview';

const VerificationScreen = ({ sessionUrl, onComplete }) => {
  return (
    <WebView
      source={{ uri: sessionUrl }}
      // Required: generic mobile user agent
      userAgent="Mozilla/5.0 (Linux; Android 10; Mobile) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36"
      // Required for camera/media
      mediaPlaybackRequiresUserAction={false}
      allowsInlineMediaPlayback={true}
      // Android-specific
      domStorageEnabled={true}
      // Performance
      androidHardwareAccelerationDisabled={false}
      androidLayerType="hardware"
      // Intercept callback
      onNavigationStateChange={(navState) => {
        if (navState.url.includes('yourapp.com/callback')) {
          const url = new URL(navState.url);
          const sessionId = url.searchParams.get('verificationSessionId');
          const status = url.searchParams.get('status');
          onComplete({ sessionId, status });
        }
      }}
    />
  );
};

export default VerificationScreen;
```> [card] [عرض توضيحي لـ React Native](https://github.com/didit-protocol/expo-didit-verification-webview)
>
> مثال للتحقق باستخدام Expo وWebView***## Flutterأضف الحزم المطلوبة إلى `pubspec.yaml`:```yaml theme={null}
dependencies:
  webview_flutter: ^4.4.0
  webview_flutter_wkwebview: ^3.9.0
  webview_flutter_android: ^3.12.0
```### التنفيذ```dart theme={null}
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'package:webview_flutter_wkwebview/webview_flutter_wkwebview.dart';
import 'package:webview_flutter_android/webview_flutter_android.dart';

class VerificationScreen extends StatefulWidget {
  final String sessionUrl;
  
  const VerificationScreen({super.key, required this.sessionUrl});

  @override
  State<VerificationScreen> createState() => _VerificationScreenState();
}

class _VerificationScreenState extends State<VerificationScreen> {
  late final WebViewController _controller;

  @override
  void initState() {
    super.initState();
    _setupWebView();
  }

  void _setupWebView() {
    late final PlatformWebViewControllerCreationParams params;
    
    if (WebViewPlatform.instance is WebKitWebViewPlatform) {
      params = WebKitWebViewControllerCreationParams(
        allowsInlineMediaPlayback: true,
        mediaTypesRequiringUserAction: const {},
      );
    } else {
      params = const PlatformWebViewControllerCreationParams();
    }

    _controller = WebViewController.fromPlatformCreationParams(params)
      ..setJavaScriptMode(JavaScriptMode.unrestricted)
      ..setUserAgent(
        'Mozilla/5.0 (Linux; Android 10; Mobile) AppleWebKit/537.36 '
        '(KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36'
      )
      ..setNavigationDelegate(
        NavigationDelegate(
          onNavigationRequest: (NavigationRequest request) {
            if (request.url.contains('yourapp.com/callback')) {
              _handleResult(request.url);
              return NavigationDecision.prevent;
            }
            return NavigationDecision.navigate;
          },
        ),
      )
      ..loadRequest(Uri.parse(widget.sessionUrl));

    // Grant camera/microphone permissions
    final platform = _controller.platform;
    platform.setOnPlatformPermissionRequest((request) {
      request.grant();
    });

    // Android-specific
    if (platform is AndroidWebViewController) {
      platform.setMediaPlaybackRequiresUserGesture(false);
    }
  }

  void _handleResult(String callbackUrl) {
    final uri = Uri.parse(callbackUrl);
    final sessionId = uri.queryParameters['verificationSessionId'];
    final status = uri.queryParameters['status'];
    
    Navigator.of(context).pop({
      'sessionId': sessionId,
      'status': status,
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Identity Verification')),
      body: WebViewWidget(controller: _controller),
    );
  }
}
```> [card] [عرض توضيحي لـ Flutter](https://github.com/didit-protocol/flutter-didit-verification-webview)
>
> مثال للتحقق باستخدام WebView في Flutter***## الإعداد الحرج### وكيل المستخدم (مطلوب)يجب عليك **ضبط** وكيل مستخدم عام للهاتف المحمول حتى تعمل WebView بشكل صحيح:```
Mozilla/5.0 (Linux; Android 10; Mobile) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36
```يضمن ذلك وصولًا صحيحًا إلى الكاميرا، وعرضًا سليمًا للواجهة، وتشغيلًا مثاليًا للوسائط.### إعدادات الوسائط (مطلوبة)| الإعداد | الغرض |
| - | - |
| `allowsInlineMediaPlayback` | يمنع ملء الشاشة للفيديو على iOS |
| `mediaPlaybackRequiresUserGesture` | يسمح ببدء الكاميرا تلقائيًا |
| `javaScriptEnabled` | مطلوب لوظائف SDK |
| `domStorageEnabled` | تخزين الجلسة على Android |***## معالجة الاستدعاءبعد التحقق، تعيد WebView التوجيه إلى رابط الاستدعاء الخاص بك مع معاملات الاستعلام:```
https://yourapp.com/callback?verificationSessionId=abc123&status=Approved
```| المعامل | الوصف |
| - | - |
| `verificationSessionId` | معرّف الجلسة الفريد |
| `status` | `Approved` أو `Declined` أو `In Review` |> [!TIP]
>
> لتجربة مستخدم أفضل، استخدم **مخطط عنوان URL مخصصًا** (مثل `myapp://verification-complete`) كرد استدعاء، وعالجه كرابط عميق في تطبيقك.***## استكشاف الأخطاء وإصلاحها> [accordion] الكاميرا لا تعمل
>
> 1. تأكد من أن قيمة `mediaPlaybackRequiresUserGesture` هي `false`
> 2. تحقق من منح أذونات الكاميرا على مستوى نظام التشغيل
> 3. تأكد من ضبط سلسلة وكيل المستخدم بشكل صحيح> [accordion] شاشة بيضاء أو مشكلات في التحميل
>
> 1. تحقق من أن عنوان URL للجلسة صالح وغير منتهٍ
> 2. تحقق من الاتصال بالإنترنت
> 3. تأكد من تفعيل JavaScript في إعدادات WebView> [accordion] عدم تشغيل الاستدعاء
>
> 1. تحقق من أن رابط الاستدعاء يطابق ما ضبطته عند إنشاء الجلسة
> 2. تأكد من ضبط مفوّض التنقل أو المستمع بشكل صحيح
> 3. جرّب ضبط `callback_method` على `"both"` عند إنشاء الجلسة***


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