Tencent Palm Mobile H5 SDK Reference
Audience: front-end / H5 engineers on the integrating side
This document helps you integrate palm capture in the browser (including mobile WebViews). The user token required by the SDK is issued by your backend via CreateSdkUserToken.
Changelog
| Version | Release Date | Changes |
|---|---|---|
| v1.4.0 | 2026-10-09 | Recognition (1:N) adapted to backend v1.4: customHeaders.AppId is required in recognition mode; the search_rgb_palm body carries that AppId and the palm image / video are encrypted with it. token may be an empty string (the gateway allows anonymous search_rgb_palm keyed by AppId; no Authorization header is sent when empty); when provided it must belong to the same app as AppId. userId is optional. Registration / verification still require token |
| v1.3.0 | 2026-09-14 | Logging aligned with the new palmreport contract: final-state trace (success / cancel / failure) is always reported; enableLogReport only controls encrypted on-site image / video diagnostic replicas. Diagnostic media presigning migrated to create_tmp_obj (with AppId in the request body). Desktop browsers with landscape windows no longer cancel acquisition as orientation change |
| v1.2.0 | 2026-08-18 | RecognitionData.sessionId; CheckAppQuality on recognition / verification; removed Params.baseUrl (API host fixed by SDK Host deployment) |
| v1.1.0 | 2026-08-16 | PalmX Web SDK surface: Params / Result / enableManager / enableImageOnly; VerificationData.sessionId; manager direction constraints; get_palm 10021 → empty palms |
| v1.0.0 | 2026-07-20 | Initial PalmX line |
Upgrading from v1.3? See "Upgrading from v1.3 to v1.4" at the end.
Introduction
The Tencent Palm Mobile Manager Web SDK is the Web platform implementation of PalmX palm biometrics. It supports registration, verification (1:1), and recognition (1:N). Capture and inference run in the browser via iframe + WebAssembly. The SDK is deployed on a dedicated SDK Host domain; host pages integrate with a single <script src> tag or the npm package.
Core Modules
The SDK consists of two core modules: Management Module and Acquisition Module.
Management Module
Palm management UI (enableManager = true, default):
- Palm state — Query left/right registration via
get_palm; support deleting registered palms - Business flow — Registration, Recognition (1:N), Verification (1:1)
- UI interaction — Guidance, results, errors, and retry
- Result handling — Shows acquisition results inside the SDK; most business errors stay in-SDK for retry
- Result callback — Calls back to the host mainly on critical errors (invalid params, token invalid, gateway auth failure, user not found) or user exit
The PalmX management module does not create users inside the SDK (no
userName/phoneNoparams). Users must already exist on PalmXAI Platform; tokens are issued viaCreateSdkUserToken. The app id is not a standalone param; it is always passed viacustomHeaders.AppId(required for recognition (1:N)).
Acquisition Module
Palm print acquisition (entered directly when enableManager = false; also used internally by the management module):
- Camera —
navigator.mediaDevices.getUserMedialive preview - AI — Detection, quality, liveness (WebAssembly)
- Guidance — Open-palm / fist prompts
- Upload — AES-128-GCM encrypted images; liveness video is recorded and uploaded by default. Client capture failure →
ErrLivenessVideoCaptureFailed (10105); server rejection →ErrLivenessVideoFailed (10102); upload / network failure →ErrNetwork (10500) - Image-only —
enableImageOnly = trueskips video upload and cloud register / search / compare, returning encryptedImageData - Log reporting — The final-state trace (success / cancel / failure) of every session is always reported to the palmreport log channel for statistics and troubleshooting;
enableLogReport = trueadditionally uploads encrypted on-site image / video diagnostic replicas (seeParams.enableLogReport) - Orientation — Rotating a touch mobile device to landscape invalidates the current acquisition (treated as
10002user cancel); desktop browser window orientation does not affect acquisition
Features
- Multiple modes — Registration, Verification (1:1), Recognition (1:N)
- Optimized AI — Detection & alignment, liveness, quality, and action recognition via WebAssembly
- Modular UI — Pre-built UI for manager and acquisition
- Origin isolation — Capture UI and wasm run in an iframe on an independent origin;
postMessagewith strict origin checks - Secure by design — Palm data encrypted before upload; tokens must be server-issued — never hard-code platform secrets in the browser
Glossary / Core Concepts
- [Palm] Single-Factor Feature Set — Palm print only. Browser cameras cannot capture palm vein; this SDK collects palm print only.
- [Palm + PalmVein] Dual-Factor Feature Set — Palm print + palm vein for professional-device enrollment. This Web SDK does not collect palm vein.
SDK Host
The SDK is deployed by the service provider on a dedicated domain (SDK Host). Host pages include the loader via <script src>. The capture iframe, wasm, and camera UI are served by the SDK Host — the host page does not need to know their internals.
https://open.intl.palm.tencent.com/palm/x/jssdk/loader/palm-mobile-manager.js— entry for<script src>https://open.intl.palm.tencent.com/palm/x/jssdk/embed/— capture iframe page (loader infers this from its own<script src>)
Important: The SDK Host MUST be on a different origin from your host page so that
MessageEvent.originchecks meaningfully secure cross-window communication. Loader and embed live on the same SDK Host.
Workflow
1. Obtain User Token
Your backend requests a short-lived token bound to the end-user UserId from Tencent PalmXAI Platform (CreateSdkUserToken), then delivers it to the client.
Recognition (1:N) does not target a specific user and needs no token: pass empty
tokenanduserId, putAppIdincustomHeaders(required), and the SDK recognizes anonymously within that app. Registration and verification (1:1) still require a token.
Production tokens must come from your own backend — never put the platform
api_keyin front-end code.
2. Start the SDK
| SDK Module | Description |
|---|---|
| Management | enableManager = true (default). Shows manager UI, then acquisition; most results handled in-SDK |
| Acquisition | enableManager = false. Direct camera capture; host dispatches the full Result |
For registration / verification, call PalmMobileManager.start with token and userId; for recognition (1:N), only AppId in customHeaders is needed (see "Recognition (1:N) Example").
3. Automated Flow
The Management Module queries palm state, shows guidance / result pages, runs acquisition by mode, and prompts retry in-SDK.
The Acquisition Module returns the full Result (including success data) via Promise / callback when done.
4. Receive Callback
Only one session at a time; concurrent calls are rejected immediately with ErrSdkRuntime (10007).
- Management: host mainly receives user exit (
10002) and critical passthrough codes (see Callback Result Codes). Success business payloads usually stay in the SDK result UI. - Acquisition: host must handle the complete result-code set.
Runtime Requirements
| Item | Requirement |
|---|---|
| Protocol | HTTPS (localhost excepted). getUserMedia requires a secure context. |
| Browser | ● Desktop: Chrome / Edge ≥ 88, Firefox ≥ 90, Safari ≥ 14 ● Mobile: iOS Safari ≥ 14, Android Chrome ≥ 88 ● Required: MediaDevices.getUserMedia, postMessage, ES2020, WebAssembly |
| iframe permissions | SDK sets allow="camera; microphone" on the iframe. Nested host iframes must allow camera at each level. |
| Node (npm only) | Node.js ≥ 18 |
Integration Steps
Prerequisites
- SDK Host URL —
https://open.intl.palm.tencent.com, assets under/palm/x/jssdk/. - HTTPS — both SDK Host and host page (except
localhost). - User & Token (registration / verification) — end user provisioned on the platform; backend issues token via
CreateSdkUserToken. - App ID (recognition (1:N)) — your app id (
AppId) on PalmXAI Platform, passed viacustomHeaders.AppId. - Privacy consent — the SDK does not show a privacy agreement or record user consent. Obtain explicit user consent on your page before calling
PalmMobileManager.start.
<script> Integration
-
Include the Loader
<!-- Loader on the SDK Host --><script src="https://open.intl.palm.tencent.com/palm/x/jssdk/loader/palm-mobile-manager.js"></script>The UMD build exposes under
window.PalmMobileManager: thePalmMobileManagerclass, plusMode/PalmDirection/ResultCode. -
Minimal example
<script>const { PalmMobileManager, Mode } = window.PalmMobileManager;const params = {token: USER_TOKEN,userId: USER_ID,// mode: Mode.Registration, // default registration// mode: 'verification', // verification: userId is 1:1 compare target// mode: 'recognition', // recognition (1:N): customHeaders.AppId required// palmDirection: 'palm_direction_unspecified',// enableManager: true, // false = direct acquisition// enableImageOnly: false,// enableLogReport: false, // true = upload encrypted diagnostic replicas// customHeaders: { AppId: APP_ID }, // app id: required for recognition, diagnostics otherwise};PalmMobileManager.start(params, (r) => {console.log('[PalmMobileManager]', r);}).then((result) => {console.log('final:', result);});</script>Zero config: the loader uses its own
<script src>origin as the embed site. As long as loader and embed share the SDK Host, the host page needs no extra setup.
npm
pnpm add palm-mobile-manager
import { PalmMobileManager, Mode, PalmDirection } from 'palm-mobile-manager';
const result = await PalmMobileManager.start({
token: USER_TOKEN,
userId: USER_ID,
// mode: Mode.Verification,
// palmDirection: PalmDirection.Left,
// enableManager: false,
});
console.log(result);
Recognition (1:N) Example
Recognition does not target a specific user: pass empty token and userId; AppId must be provided in customHeaders, otherwise the call returns ErrInvalidParams (10001) immediately. Use enableManager = false so the host page receives the full RecognitionData.
import { PalmMobileManager, Mode, ResultCode } from 'palm-mobile-manager';
const result = await PalmMobileManager.start({
token: '', // may be empty: gateway allows anonymous access by AppId; no Authorization header
userId: '', // 1:N is not user-specific (the TS type requires the field; pass an empty string)
mode: Mode.Recognition,
customHeaders: { AppId: APP_ID }, // required: written into the search_rgb_palm body and used as the image / video encryption factor
enableManager: false,
});
if (result.code === ResultCode.Success) {
// Matched user's userId / score / sessionId.
// Hand sessionId to your server to verify the result; do not trust userId alone.
console.log(result.data);
}
If a
tokenis also passed, it must belong to the same app asAppId; otherwise the backend returns2060205(mapped to10012).
Local Integration Testing
Point the host page's <script src> at the SDK Host. The host page may run on http://localhost; the camera is opened by the SDK Host HTTPS iframe:
<script src="https://open.intl.palm.tencent.com/palm/x/jssdk/loader/palm-mobile-manager.js"></script>
Test tokens can be issued by your test backend via CreateSdkUserToken, or see "Quick Start for Testing Environments" below.
API Reference
PalmMobileManager.start(params, callback?)
Starts one management / acquisition session and returns Promise<Result>. callback and Promise receive the same Result. Only one session at a time; concurrent calls return ErrSdkRuntime (10007).
| Positional | Type | Required | Description |
|---|---|---|---|
params | Params | ✅ | See below |
callback | (result: Result) => void | Optional; Promise still resolves with the same result |
PalmMobileManager.back()
Sends a back command to the active embed (same semantics as the in-UI back control). No-op if no session.
PalmMobileManager.version
Static string, the SDK version, currently 1.4.0 (same as the product-line version in this document).
Params
Startup validates non-empty fields (
token/userIdfor registration / verification;customHeaders.AppIdfor recognition); failure returnscode=10001. Prefer theuserIdformat below; otherwise the backend may map to10018.
Required Fields by Mode
| Parameter | Registration | Verification (1:1) | Recognition (1:N) |
|---|---|---|---|
token | ✅ | ✅ | may be empty |
userId | ✅ user to enroll | ✅ compare target | may be empty |
customHeaders.AppId | optional | optional | ✅ |
Identity Parameters
| Parameter | Type | Description |
|---|---|---|
token | string | User identity token (issued by backend CreateSdkUserToken). May be an empty string in recognition mode (anonymous 1:N keyed by customHeaders.AppId). |
userId | string | Unique user id. • registration: user to enroll• verification: 1:1 compare target (CompareUserId)• recognition: optional (1:N is not user-specific)Recommended format: 1–64 chars, [A-Za-z0-9_-] only, no whitespace. |
Optional Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
mode | Mode | Registration ('registration') | • Mode.Registration ('registration')• Mode.Verification ('verification')• Mode.Recognition ('recognition') |
palmDirection | PalmDirection | Unspecified | • PalmDirection.Unspecified ('palm_direction_unspecified')• PalmDirection.Left ('left')• PalmDirection.Right ('right') |
enableManager | boolean | true | true = management module; false = acquisition only. |
enableImageOnly | boolean | false | When true, return encrypted ImageData only — no video upload, no register / search / compare. |
enableLogReport | boolean | false | When true, additionally upload AES-128-GCM encrypted on-site image / video diagnostic replicas (presigned via create_tmp_obj, uploaded directly to object storage) for troubleshooting. The final-state trace log is not gated by this switch and is always reported (statistics baseline). |
customHeaders | Record<string, string> | {} | Extra HTTP headers. AppId (case-insensitive key) is the app id:• required for recognition; when token is provided it must match the app that issued it — the SDK writes it into the search_rgb_palm body and uses it as the image / video encryption factor; otherwise the backend returns 2060205 (mapped to 10012)• other modes use it for diagnostic replica upload ( create_tmp_obj)Note: customHeaders are attached as-is to every SDK request. Do not pass Authorization: it overrides the Bearer <token> the SDK builds from token. The Web SDK has no baseUrl; requests always go to the SDK Host gateway, authenticated by token. |
Difference vs. native SDKs (H5 characteristic): The Web SDK does not expose
baseUrl. The API endpoint is decided by the embed / SDK Host at deployment time: same-origin relative/palm/*via Ingress / reverse proxy by default; when the page host isapp.*, the SDK rewrites to matchingopen.*. The host page cannot override it. To connect to a different backend environment, use the corresponding SDK Host.vs older PalmX docs: no
userName/phoneNo/targetUserId;appIdis passed viacustomHeaders.AppId, same as native. Verification target isuserId.
Result
interface Result {
code: number;
message: string;
data?: RegistrationData | RecognitionData | VerificationData | ImageData;
traceId?: string;
}
| Property | Type | Description |
|---|---|---|
code | number | Result code (see below). |
message | string | Debug message. |
data | ResultData | undefined | Success payload; shape depends on mode / enableImageOnly. |
traceId | string | undefined | Request trace id (may be present on failure). |
ResultData
interface RegistrationData {
userId: string;
/** Temporary registration-result lookup credential (RegisterRgbPalmRsp.SessionId, ~2h TTL) */
sessionId?: string;
/** Palm direction enrolled in this session */
palmDirection?: PalmDirection;
}
interface RecognitionData {
userId: string;
score: number;
palmDirection?: PalmDirection;
/** Temporary search-result lookup credential (SearchRgbPalmRsp.SessionId, ~2h TTL) */
sessionId?: string;
}
interface VerificationData {
isMatch: boolean;
score: number;
palmDirection?: PalmDirection;
/** Temporary compare-result lookup credential (CompareRgbPalmRsp.SessionId, ~2h TTL) */
sessionId?: string;
}
interface ImageData {
/** Serialized acquisition JSON (image fields AES-128-GCM encrypted) */
payload: string;
}
Hand
sessionIdto your server and verify the result via GetSessionResult.
Callback Result Codes (Management Module)
With enableManager = true, the host mainly receives:
| Code | Scenario | Suggested action |
|---|---|---|
10002 | User exit (e.g. back from manager root) | Treat as cancel |
10001 | Invalid parameters | Validate required fields / mode (e.g. customHeaders.AppId missing in recognition) |
10012 | Token invalid or expired; in recognition, token and AppId belong to different apps | Re-issue token / check AppId |
10021 | User does not exist (passthrough) | Check user / re-login |
10401 | Gateway auth failure | Check gateway JWT / contact technical support |
Token / gateway auth failures during the manager stage (before acquisition starts) exit immediately with a callback; during acquisition, the management module first shows the failure result page and calls back after the user exits (same result code). Successful business payloads stay in the manager result UI by default; use
enableManager = falseif the host needs the full successdata.
Complete Result Code Reference
Acquisition module (
enableManager = false) does not swallow codes — the host must dispatch the full set:
Expand all result codes
Common
| Code | Enum | Notes |
|---|---|---|
| 0 | Success | Success |
| 10000 | ErrUnknown | Unknown error |
| 10001 | ErrInvalidParams | Invalid parameters, e.g. customHeaders.AppId missing in recognition (manager callbacks) |
| 10002 | ErrUserCancelled | User cancelled (manager callbacks) |
| 10003 | ErrCameraPermissionDenied | Camera permission denied |
| 10004 | ErrCameraInitFailed | Camera init failed |
| 10005 | ErrCameraPreviewUnsupported | Unsupported preview size |
| 10006 | ErrSdkInitFailed | SDK / wasm init failed |
| 10007 | ErrSdkRuntime | Runtime error (incl. concurrent session) |
| 10008 | ErrAcquisitionTimeout | Acquisition timeout (30s) |
| 10012 | ErrUserTokenInvalid | Token invalid/expired (callback / may exit immediately) |
| 10016 | ErrLicenseValidationFailed | License validation failed |
| 10018 | ErrUserIdInvalid | Invalid user id format |
| 10020 | ErrAppDisabled | App disabled |
| 10021 | ErrUserNotExist | User not found (manager callbacks; manager get_palm treats as empty palms) |
Registration
| Code | Enum | Notes |
|---|---|---|
| 10100 | ErrLivenessFailed | Liveness failed |
| 10101 | ErrQualityFailed | Quality failed |
| 10102 | ErrLivenessVideoFailed | Liveness video rejected by server |
| 10103 | ErrAlreadyBind | Palm already registered |
| 10104 | ErrHighSimilarity | High similarity with existing user |
| 10105 | ErrLivenessVideoCaptureFailed | Client could not record liveness video (browser / insecure context / recorder lost) |
Recognition
| Code | Enum | Notes |
|---|---|---|
| 10200 | ErrUserNotRecognized | User not recognized |
Verification
| Code | Enum | Notes |
|---|---|---|
| 10200 | ErrUserNotRecognized | No palm feature of the target user found in the compare library (shared with recognition) |
| 10300 | ErrTargetUserNotFound | Target user not found |
| 10301 | ErrTargetUserUnregistered | Target has no registered palm |
| 10302 | ErrTargetUserPalmDirectionUnregistered | Target missing current palm direction |
Network
| Code | Enum | Notes |
|---|---|---|
| 10401 | ErrUnauthorized | Gateway unauthorized (callback / may exit immediately) |
| 10500 | ErrNetwork | Network error (incl. unmapped backend codes) |
Architecture
Host Page
└─ PalmMobileManager.start(params, callback?)
└─ <iframe src="https://open.intl.palm.tencent.com/palm/x/jssdk/embed/" allow="camera; microphone">
└─ Manager View → Acquisition View
└─ getUserMedia + wasm + Tencent PalmXAI Platform
←── postMessage { ns:'palm-mobile-manager', v:1, msg:{ type:'result', payload } } ──
- Loader ↔ Embed enforce bidirectional origin checks.
- Cloud APIs (when not
enableImageOnly):register_rgb_palm/search_rgb_palm/compare_rgb_palm; recognition and verification requests sendCheckAppQuality: true. - Log channel: the final-state trace (success / cancel / failure) is always reported to
/palm/openai/palm/palmreport/logs(OTLP,report_source=3,device_snis a browser-persistent random id). WithenableLogReport = true, encrypted on-site image / video diagnostic replicas are additionally presigned via/palm/openai/palm/palmreport/create_tmp_obj(AppIdin the request body) and uploaded directly to object storage. The SDK awaits the log queue before returning the result — destroying the iframe does not truncate the final trace.
Full sequence diagram
Security Warning
Production Environment Security Requirements
Never hard-code platform account secrets in production browser code.
All calls that need platform secrets (e.g. CreateSdkUserToken) must run on your server. The browser only receives a short-lived token.
Verifying Recognition (1:N) Results
The AppId passed for recognition (1:N) is an app identifier, not a secret, and may live in the front end. After anonymous recognition the userId in the browser callback can be tampered with, so hand the sessionId returned on a successful recognition (~2h TTL) to your server to verify the result — do not trust the userId in the browser callback alone.
Session Uniqueness
Only one Web SDK session at a time. Concurrent PalmMobileManager.start() calls are rejected with ErrSdkRuntime (10007).
Quick Start for Testing Environments
For local / internal / isolated demo only. In production, tokens must be issued dynamically by your backend.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
<title>Palm H5 Test</title>
</head>
<body>
<button id="startBtn">Start</button>
<pre id="result"></pre>
<script src="https://open.intl.palm.tencent.com/palm/x/jssdk/loader/palm-mobile-manager.js"></script>
<script>
// [TEST ONLY] do not embed production tokens in pages
const USER_TOKEN = 'sut_xxx'; // required for registration / verification; may be empty for recognition
const USER_ID = 'YourUserId'; // required for registration / verification; may be empty for recognition
const APP_ID = 'YourAppId'; // required for recognition (1:N)
const MODE = 'registration'; // 'registration' | 'verification' | 'recognition'
const { PalmMobileManager } = window.PalmMobileManager;
const resultEl = document.getElementById('result');
document.getElementById('startBtn').addEventListener('click', async () => {
try {
const result = await PalmMobileManager.start({
token: USER_TOKEN,
userId: USER_ID,
mode: MODE,
customHeaders: { AppId: APP_ID },
enableManager: false, // easier to observe full Result in tests
});
resultEl.textContent = JSON.stringify(result, null, 2);
} catch (err) {
resultEl.textContent = `Error: ${err?.code ?? ''} ${err?.message ?? err}`;
}
});
</script>
</body>
</html>
Upgrading from v1.3 to v1.4
v1.4 changes are concentrated in recognition (1:N). Integrations that only use registration and verification (1:1) can upgrade without code changes.
| # | Change | Impact | Code change needed |
|---|---|---|---|
| 1 | Recognition (1:N) requires customHeaders.AppId | Breaking: returns 10001 immediately if missing | ✅ Required if you use recognition |
| 2 | Recognition palm images and video are encrypted with AppId | Handled inside the SDK; backend decrypts by the AppId in the body | ❌ As long as the correct AppId is passed |
| 3 | Recognition no longer needs token; userId is optional | Optional: no need to issue tokens for recognition | Recommended |
| 4 | RegistrationData adds sessionId and palmDirection | New fields, backward compatible | ❌ Use as needed |
| 5 | PalmMobileManager.version changes from 0.0.1 to 1.4.0 | Only affects version-based logic | Depends |
| 6 | Token failure during acquisition shows the failure result first, then calls back | Callback arrives slightly later in the management module | ❌ |
Recognition call diff:
const result = await PalmMobileManager.start({
- token: userToken, // v1.3: recognition also required a token
- userId: 'placeholder', // v1.3: must be non-empty
+ token: '', // v1.4: may be empty for recognition
+ userId: '',
mode: Mode.Recognition,
+ customHeaders: { AppId: APP_ID }, // v1.4: required for recognition
enableManager: false,
});
Upgrade checklist:
- Reference the v1.4.0 loader or npm package
- Every
mode = recognitioncall passescustomHeaders.AppId -
AppIdmatches the current environment (test / production) - (Optional) Remove logic that issues a token or fills a placeholder
userIdfor recognition - Verify recognition results on your server with
sessionId - Update any logic that checks
version === '0.0.1' - Regression-test registration, verification, and recognition
FAQ:
| Symptom | Likely cause | Fix |
|---|---|---|
Recognition returns 10001 right after start | customHeaders.AppId missing or empty | Pass AppId |
Recognition returns 10012 | AppId does not exist in this environment (e.g. a test ID used in production); or a token was passed but is invalid or belongs to another app | Check AppId and environment; you may omit the token for recognition |
Recognition keeps returning 10200 (not recognized) | AppId belongs to a different app whose library does not contain the user's palm | Use the same AppId as during registration |
Registration / verification returns 10001 | These modes still require non-empty token and userId | Pass them as before |
Next Steps & Support
- Server APIs: token issuance, palm query / deletion, and recognition result verification — see the KYC Open API Integration Guide
- Native app integration: Android / iOS / Flutter — see Mobile (App) SDK
- Support: contact your technical support representative