Imagine: a client signs a contract via a mobile app and later disputes its authenticity. Without biometric metadata, such disputes are impossible to resolve. We encountered this in a fintech project — had to rebuild the signature module from scratch. Our approach: combine trajectory capture with pressure and velocity, bind to the document hash, and maintain an audit trail. Mobile apps increasingly require an embedded handwritten signature module — from banking documents to medical records. But the illusion of "just a picture" is dangerous: a signature on screen has no legal weight without binding to identity, document, and time. We solve this at the Android (Kotlin, Jetpack Compose) and iOS (Swift, SwiftUI) level, using low-level trajectory capture and biometric metadata. Our experience — over 10 projects integrating signatures into document workflows, guaranteeing stable operation on all devices. The cost of such a solution pays off by reducing the risk of litigation.
Capturing the Handwritten Signature
Trajectory collection is the foundation. We need not just touchMove coordinates but the entire event stream with pressure, velocity, and timestamps. This allows animated reproduction of the signature and collection of biometric metadata.
Android — low-level input:
override fun onTouchEvent(event: MotionEvent): Boolean { val x = event.x val y = event.y val pressure = event.pressure // 0.0 - 1.0 val timestamp = event.eventTime when (event.action) { MotionEvent.ACTION_DOWN -> startStroke(x, y, pressure, timestamp) MotionEvent.ACTION_MOVE -> { for (i in 0 until event.historySize) { addHistoricalPoint( event.getHistoricalX(i), event.getHistoricalY(i), event.getHistoricalPressure(i), event.getHistoricalEventTime(i) ) } addPoint(x, y, pressure, timestamp) } MotionEvent.ACTION_UP -> endStroke(x, y, pressure, timestamp) } return true } event.historySize is critical — between two ACTION_MOVE events, the system batches intermediate points. Ignoring historical points produces jagged strokes instead of smooth curves.
iOS — UIBezierPath with Bezier smoothing:
func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) { guard let touch = touches.first else { return } let currentPoint = touch.location(in: self) let previousPoint = touch.previousLocation(in: self) let force = touch.force / touch.maximumPossibleForce let midPoint = CGPoint( x: (currentPoint.x + previousPoint.x) / 2, y: (currentPoint.y + previousPoint.y) / 2 ) path.addQuadCurve(to: midPoint, controlPoint: previousPoint) setNeedsDisplay() } For Apple Pencil we use predictedTouches(for:) — without predicted points, the response at 120 Hz feels laggy.
Variable Line Thickness
A professional signature looks natural when stroke thickness varies with pressure and velocity. The math is simple: width = baseWidth + pressure * maxExtraWidth. At high speed — thin line; at slow movement — thick.
fun calculateStrokeWidth(pressure: Float, velocity: Float): Float { val pressureComponent = pressure * MAX_PRESSURE_WIDTH val velocityComponent = (1f - velocity.coerceIn(0f, 1f)) * MAX_VELOCITY_WIDTH return BASE_WIDTH + pressureComponent * 0.6f + velocityComponent * 0.4f } How to Ensure Legal Validity? — Biometric Metadata
To strengthen legal force, we collect metadata of the signing process:
- Timestamps of each stroke
- Segment movement speed
- Pressure (if device supports)
- Duration of each stroke and pauses between them
- Total signing time
More on metadata collection
Each stroke is captured with millisecond precision. We use behavioral biometrics — the unique pressure and speed pattern is hard to forge. Without this data, the signature is just a PNG.This data is stored in the database and can be used in court to dispute signature authenticity — behavioral biometrics. Without it, the signature is just a PNG.
Binding to the Document
The signature drawing alone is useless. We need to:
- Capture the document hash before signing (SHA-256 of PDF or text content)
- Attach the signature (PNG + trajectory metadata) to this hash
- Store on the server with timestamp and signer identifier
- Optionally: embed the signature into PDF via iText (Java/Android) or PDFKit (iOS)
Server record:
{ "document_hash": "sha256:abc123...", "signer_id": "user-uuid", "signed_at": "timestamp", "ip_address": "1.2.3.4", "device_fingerprint": "...", "signature_image_url": "...", "stroke_data_encrypted": "...", "session_metadata": { "duration_ms": 4200, "stroke_count": 5, "avg_pressure": 0.72 } } Why Not Skimp on Biometrics? Comparison of Approaches
| Criterion | Ready-made SDK (SignaturePad, etc.) | Custom implementation |
|---|---|---|
| Time to integration | 1–2 days | 3–4 days |
| Biometric metadata | None | Full collection |
| Variable thickness with pressure | Limited | Customizable |
| PKI integration | No | Possible |
| Legal strength | Only simple EP | Qualified EP with audit trail |
Ready-made SDKs are justified for simple scenarios (simple EP), but if qualified EP with court-disputability is required, a custom implementation is 2–3 times more reliable.
Additional Audit Data
| Parameter | Value |
|---|---|
| Points per signature | 500–1500 |
| Metadata size | 2–5 KB |
| Time precision | ±1 ms |
| Supported devices | iOS 14+, Android 8+ |
PDF Integration
On iOS: PDFKit + CGContext to draw the signature over the PDF page. For professional embedding with AcroForm fields — third-party library PSPDFKit or server-side iText via API.
On Android: PdfRenderer for display, embedding via iText Android or Apache PDFBox.
Important: visual embedding of a signature into PDF ≠ digital signature (PKI). These are different. For a legally binding PDF document, a PKI signature is required — the handwritten signature is added as an additional visual element.
What's Included in the Work
When ordering turnkey, you get:
- Signature drawing component for iOS and Android with pressure support and smoothing
- Server module for document binding (hash, metadata, timestamp)
- PDF integration (signature embedding)
- API documentation and integration examples
- 2 weeks of technical support
We provide a project estimate in one day. Order a custom implementation — get full control over biometrics. Contact us for a consultation.
Timelines: 3–4 days for one platform, 5–7 days for both. Get a consultation.







