---
Source: https://docs.microblink.com/blinkcard/scan-camera
Title: Scan a card via camera
Description: Scan a payment card in real time using the device camera with BlinkCard
---

# Scan a card via camera

BlinkCard includes a built-in scanning UI that opens the camera, guides the user with real-time feedback, handles the front-to-back transition, and returns the extracted card data through a result callback.

## Initialize and scan

On Web, call `createBlinkCard` with your license key.
This loads the scanning engine, opens the camera, and mounts the scanning UI in one step.

On Android, initialize the SDK and then show `BlinkCardCameraScanningScreen`, which owns its own camera lifecycle.

On iOS, create the SDK, build a `BlinkCardUXModel` from a `BlinkCardAnalyzer`, observe its published `$result`, and present `BlinkCardUXView`.

<Tabs queryString="platform">
  <TabItem value="web" label="Web (JS)" default>

```ts

const blinkCard = await createBlinkCard({
  licenseKey: "your-license-key",
});

blinkCard.addOnResultCallback((result) => {
  console.log("Card number:", result.cardAccounts[0].cardNumber);
  void blinkCard.destroy();
});
```

  </TabItem>
  <TabItem value="android" label="Android (Kotlin)">

```kotlin
val sdk = BlinkCardSdk.initializeSdk(
    context,
    BlinkCardSdkSettings(licenseKey = "your-license-key")
).getOrThrow()

BlinkCardCameraScanningScreen(
    blinkCardSdk = sdk,
    onScanningSuccess = { result ->
        val cardNumber = result.cardAccounts[0].cardNumber
    },
    onScanningCanceled = { }
)
```

  </TabItem>
  <TabItem value="ios" label="iOS (Swift)">

```swift
let sdk = try await BlinkCardSdk.createBlinkCardSdk(
    withSettings: BlinkCardSdkSettings(licenseKey: "your-license-key")
)

let analyzer = try await BlinkCardAnalyzer(sdk: sdk)
let uxModel = BlinkCardUXModel(analyzer: analyzer)

uxModel.$result
    .sink { resultState in
        if let result = resultState?.scanningResult {
            let cardNumber = result.cardAccounts[0].cardNumber
        }
    }
    .store(in: &cancellables)

// Present the scanning UI:
BlinkCardUXView(viewModel: uxModel)
```

  </TabItem>
</Tabs>

For installation, license setup, and hosting the WASM resources, see the [quickstart](./quickstart.md).

## Embed the scanning UI

On Web, the scanning UI mounts into `document.body` and covers the screen by default.
To render it inside a specific element, pass `targetNode`.

On Android, place `BlinkCardCameraScanningScreen` anywhere in your Compose hierarchy.
It renders within the layout you give it, so you control where the scanning UI appears.

On iOS, embed `BlinkCardUXView` in your SwiftUI view hierarchy.
It renders within the container you place it in, so you control where the scanning UI appears.

<Tabs queryString="platform">
  <TabItem value="web" label="Web (JS)" default>

```ts
const blinkCard = await createBlinkCard({
  licenseKey: "your-license-key",
  targetNode: document.getElementById("scanner-container") ?? undefined,
});
```

  </TabItem>
  

<!-- interactive component omitted -->


  

<!-- interactive component omitted -->


</Tabs>

## Skip the onboarding guide

By default, BlinkCard shows an onboarding guide before scanning begins.
On Web, disable it to start frame capture as soon as the camera is ready.

On Android, onboarding and help behavior is configured through the optional `uxSettings: BlinkCardUxSettings` parameter of `BlinkCardCameraScanningScreen`.

On iOS, onboarding and help behavior is configured through the optional `uxSettings: ScanningUXSettings` parameter of `BlinkCardUXModel(analyzer:uxSettings:)`.

<Tabs queryString="platform">
  <TabItem value="web" label="Web (JS)" default>

```ts
const blinkCard = await createBlinkCard({
  licenseKey: "your-license-key",
  feedbackUiOptions: {
    showOnboardingGuide: false,
  },
});
```

  </TabItem>
  

<!-- interactive component omitted -->


  

<!-- interactive component omitted -->


</Tabs>

## Handle errors

On Web, register an error callback to handle failures during scanning.

On Android, SDK initialization returns a `Result`; handle initialization failures where you call `getOrThrow()`, and handle cancellation through the `onScanningCanceled` callback of `BlinkCardCameraScanningScreen`.

On iOS, SDK and analyzer creation are throwing async calls; handle failures with `try`/`catch` where you create them, and observe `$result` for the scanning outcome.

<Tabs queryString="platform">
  <TabItem value="web" label="Web (JS)" default>

```ts
blinkCard.addOnErrorCallback((error) => {
  console.error("Scanning error:", error);
  void blinkCard.destroy();
});
```

  </TabItem>
  <TabItem value="android" label="Android (Kotlin)">

```kotlin
val result = BlinkCardSdk.initializeSdk(
    context,
    BlinkCardSdkSettings(licenseKey = "your-license-key")
)

result.onFailure { error ->
    // Handle initialization failure.
}
```

Handle user cancellation through the `onScanningCanceled` callback of `BlinkCardCameraScanningScreen`.

  </TabItem>
  <TabItem value="ios" label="iOS (Swift)">

```swift
do {
    let sdk = try await BlinkCardSdk.createBlinkCardSdk(
        withSettings: BlinkCardSdkSettings(licenseKey: "your-license-key")
    )
    let analyzer = try await BlinkCardAnalyzer(sdk: sdk)
    // Continue setup.
} catch {
    // Handle initialization failure.
}
```

  </TabItem>
</Tabs>

## Clean up

On Web, when scanning is complete or the user cancels, call `destroy` to release the camera, engine, and UI.

On Android, `BlinkCardCameraScanningScreen` owns its camera lifecycle, so no explicit cleanup is needed.

On iOS, `BlinkCardUXView` releases camera resources when dismissed, so no explicit cleanup is needed.

<Tabs queryString="platform">
  <TabItem value="web" label="Web (JS)" default>

```ts
await blinkCard.destroy();
```

  </TabItem>
  

<!-- interactive component omitted -->


  

<!-- interactive component omitted -->


</Tabs>

## Related articles

- [Scan a card from a static image](./scan-image.md)
- [Extract specific fields](./extract-fields.md)


Last updated on Jun 18, 2026
