PlateVision SDK
Real-time, offline license plate recognition for iOS, Android & Flutter.
PlateVision is a mobile SDK delivering accurate, real-time ALPR entirely on-device. No cloud round-trips, no per-scan cost, no connectivity required while scanning.
You need an API key. Create a free account — no credit card required.
Quickstart
Scan plates in your iOS app in under 5 minutes.
- Get your credentials
Sign up and copy your API key and secret from the dashboard.
- Build and add the framework
Run
./build.shfrom the Framework folder, drag the resultingPlateVisionSDK.xcframeworkinto Xcode, set Embed & Sign. - Add camera permission
Add
NSCameraUsageDescriptiontoInfo.plist. - Activate and scan
import PlateVisionSDK PlateVisionSDK.shared.activate(apiKey: "pv_live_...", secretKey: "sk_...") { result in guard case .success(let l) = result, l.isValid else { return } PlateVisionSDK.shared.delegate = self PlateVisionSDK.shared.startScanning() } func plateVision(_ sdk: PlateVisionSDK, didDetect result: PVDetectionResult) { print(result.plateText, result.confidencePercent) }
Add the preview. Use PVCameraPreview(sdk: .shared) in SwiftUI or access PlateVisionSDK.shared.previewLayer for UIKit.
Authentication
Every SDK call is authenticated with an API key + secret key pair from your dashboard.
| Credential | Format | Notes |
|---|---|---|
apiKey | pv_live_... | Identifies your app. Safe to bundle in the binary. |
secretKey | sk_... | Authenticates activation. Keep private, never log. |
Never commit keys to source control. Use environment variables or a gitignored config file.
iOS SDKiOS
Installation
Binary XCFramework for iOS 16+ (arm64 device + arm64/x86_64 Simulator).
cd PlateVisionSDK/Framework
chmod +x build.sh && ./build.sh
# Outputs: build/PlateVisionSDK.xcframeworkThen drag PlateVisionSDK.xcframework into Xcode → set Embed & Sign → add NSCameraUsageDescription to Info.plist.
Swift Package Manager
.package(url: "https://github.com/platevision/platevision-ios-sdk", from: "1.0.0")
Activation
PlateVisionSDK.shared.activate(apiKey: key, secretKey: secret) { result in switch result { case .success(let l) where l.isValid: // ready case .failure(let e): print(e) default: break } }
Configuration
var config = PVConfiguration.default config.region = .us config.minimumConfidence = 0.70 config.deduplicationWindow = 3.0 config.enableSound = true config.scanROI = CGRect(x:0.07, y:0.40, width:0.86, height:0.20) PlateVisionSDK.shared.configure(config)
| Property | Type | Default | Description |
|---|---|---|---|
region | PVRegion | .auto | Country hint for validation. |
minimumConfidence | Float | 0.60 | OCR threshold (0–1). |
deduplicationWindow | TimeInterval | 2.0 s | Suppress duplicate detections. |
enableSound | Bool | true | System tick on each hit. |
scanROI | CGRect | centre 86×20% | Normalised pixel-buffer crop rect. |
Delegate
public protocol PlateVisionDelegate: AnyObject { func plateVision(_ sdk: PlateVisionSDK, didDetect result: PVDetectionResult) func plateVision(_ sdk: PlateVisionSDK, didChangeState state: PVState) func plateVisionDidFailLicence(_ sdk: PlateVisionSDK) }
| PVDetectionResult | Type | Description |
|---|---|---|
plateText | String | Uppercased stripped plate number |
confidence | Float | OCR confidence 0–1 |
confidencePercent | Int | confidence × 100 |
boundingBox | CGRect | Normalised Vision rect within scan ROI |
timestamp | Date | Time of detection |
region | PVRegion | Active region at time of detection |
Camera UI
ZStack {
PVCameraPreview(sdk: .shared).ignoresSafeArea()
// overlay: scan guide, result card, controls...
}if let layer = PlateVisionSDK.shared.previewLayer { layer.frame = view.bounds view.layer.insertSublayer(layer, at: 0) }
Full API Reference
| Method / Property | Description |
|---|---|
activate(apiKey:secretKey:completion:) | Validate credentials. Once per launch. |
configure(_ config:) | Apply config any time. |
startScanning() | Request camera permission + start. |
stopScanning() | Stop and tear down session. |
pause() / resume() | Suspend/restore without teardown. |
captureOnce() | Detect one plate then auto-pause. |
delegate | PlateVisionDelegate receiver. |
state | .idle / .running / .paused / .permissionDenied / .error |
previewLayer | AVCaptureVideoPreviewLayer (set after startScanning). |
licenceInfo | PlateVisionLicence (set after activation). |
Android SDKAndroid
dependencies { implementation("io.platevision:sdk-android:1.0.0") }PlateVisionSDK.getInstance().activate(context=this, apiKey="pv_live_...", secretKey="sk_...") { result -> if(result.isSuccess) { PlateVisionSDK.getInstance().startScanning(lifecycleOwner=this, previewView=binding.pv, onDetection = { p -> Log.d("PV", p.plateText) }) } }
Flutter SDKFlutter
dependencies: platevision_sdk: ^1.0.0
final l = await PlateVisionSDK.activate(apiKey:'pv_live_...', secretKey:'sk_...'); PlateVisionCamera( onDetection: (r) => print(r.plateText), config: PVConfig(region: PVRegion.auto, minimumConfidence: 0.7), )
Regions
| Region | Enum | Length | Example |
|---|---|---|---|
| Auto (global) | .auto | 5–10 | Any valid plate |
| US / Canada | .us | 5–8 | ABC1234, 353-42T |
| United Kingdom | .uk | 5–7 | AB12CDE |
| Europe | .europe | 5–8 | AB1234CD |
| Australia | .australia | 5–7 | ABC123 |
| India | .india | 8–10 | MH01AB1234 |
| Middle East | .middleEast | 5–8 | ABC12345 |
Plate validation pipeline
- Clean — uppercase, strip spaces, dashes, dots
- Length — per-region min/max bounds
- Alphanumeric — reject symbols
- Mix check — must have ≥1 letter AND ≥1 digit
- Run check — reject 4+ identical consecutive chars
- False-positive list — block common OCR noise words
- Region regex — country-specific pattern (when region is not .auto)
Region of interest
scanROI is a normalised rect (0–1, origin top-left) used to physically crop the pixel buffer before OCR. Only pixels inside this rectangle are passed to Vision — text outside is genuinely invisible to the engine.
// Default: 86% wide, 20% tall, vertically centred config.scanROI = CGRect(x:0.07, y:0.40, width:0.86, height:0.20)
Offline mode
All OCR inference runs on-device. Licence validation only needs internet once — on first activation. Results are cached; the SDK is fully offline thereafter.
Critical for parking garages, tunnels, and any environment where connectivity is unreliable.
Changelog
v1.0.0 — March 2026 Latest
- Initial public release
- iOS SDK: AVFoundation + Vision, fully offline
- 7-stage plate validation with per-region patterns
- Pixel buffer ROI cropping
- 7 regions / 90+ country support
- SwiftUI PVCameraPreview + UIKit preview layer
- API key + secret activation with offline fallback
- Configurable confidence, deduplication, sound, ROI
- Single-shot captureOnce() mode
Support
- Email: support@platevision.io
- Get started: Create a free account
- GitHub: github.com/platevision
Pro & Enterprise: same-day response. Starter: 2–3 business days.