PlateVision SDK

Real-time, offline license plate recognition for iOS, Android & Flutter.

🍎 iOS 16+ 🤖 Android 8+ 💙 Flutter 3+ ✈️ Offline 🌎 90+ Countries

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.

  1. Get your credentials

    Sign up and copy your API key and secret from the dashboard.

  2. Build and add the framework

    Run ./build.sh from the Framework folder, drag the resulting PlateVisionSDK.xcframework into Xcode, set Embed & Sign.

  3. Add camera permission

    Add NSCameraUsageDescription to Info.plist.

  4. Activate and scan
swift
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.

CredentialFormatNotes
apiKeypv_live_...Identifies your app. Safe to bundle in the binary.
secretKeysk_...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).

bash — build the framework
cd PlateVisionSDK/Framework
chmod +x build.sh && ./build.sh
# Outputs: build/PlateVisionSDK.xcframework

Then drag PlateVisionSDK.xcframework into Xcode → set Embed & Sign → add NSCameraUsageDescription to Info.plist.

Swift Package Manager

Package.swift
.package(url: "https://github.com/platevision/platevision-ios-sdk", from: "1.0.0")

Activation

swift
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

swift
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)
PropertyTypeDefaultDescription
regionPVRegion.autoCountry hint for validation.
minimumConfidenceFloat0.60OCR threshold (0–1).
deduplicationWindowTimeInterval2.0 sSuppress duplicate detections.
enableSoundBooltrueSystem tick on each hit.
scanROICGRectcentre 86×20%Normalised pixel-buffer crop rect.

Delegate

swift
public protocol PlateVisionDelegate: AnyObject {
    func plateVision(_ sdk: PlateVisionSDK, didDetect result: PVDetectionResult)
    func plateVision(_ sdk: PlateVisionSDK, didChangeState state: PVState)
    func plateVisionDidFailLicence(_ sdk: PlateVisionSDK)
}
PVDetectionResultTypeDescription
plateTextStringUppercased stripped plate number
confidenceFloatOCR confidence 0–1
confidencePercentIntconfidence × 100
boundingBoxCGRectNormalised Vision rect within scan ROI
timestampDateTime of detection
regionPVRegionActive region at time of detection

Camera UI

swift — SwiftUI
ZStack {
    PVCameraPreview(sdk: .shared).ignoresSafeArea()
    // overlay: scan guide, result card, controls...
}
swift — UIKit
if let layer = PlateVisionSDK.shared.previewLayer {
    layer.frame = view.bounds
    view.layer.insertSublayer(layer, at: 0)
}

Full API Reference

Method / PropertyDescription
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.
delegatePlateVisionDelegate receiver.
state.idle / .running / .paused / .permissionDenied / .error
previewLayerAVCaptureVideoPreviewLayer (set after startScanning).
licenceInfoPlateVisionLicence (set after activation).

Android SDKAndroid

build.gradle.kts
dependencies { implementation("io.platevision:sdk-android:1.0.0") }
kotlin
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

pubspec.yaml
dependencies:
  platevision_sdk: ^1.0.0
dart
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

RegionEnumLengthExample
Auto (global).auto5–10Any valid plate
US / Canada.us5–8ABC1234, 353-42T
United Kingdom.uk5–7AB12CDE
Europe.europe5–8AB1234CD
Australia.australia5–7ABC123
India.india8–10MH01AB1234
Middle East.middleEast5–8ABC12345

Plate validation pipeline

  1. Clean — uppercase, strip spaces, dashes, dots
  2. Length — per-region min/max bounds
  3. Alphanumeric — reject symbols
  4. Mix check — must have ≥1 letter AND ≥1 digit
  5. Run check — reject 4+ identical consecutive chars
  6. False-positive list — block common OCR noise words
  7. 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.

swift
// 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

Pro & Enterprise: same-day response. Starter: 2–3 business days.