> ## Documentation Index
> Fetch the complete documentation index at: https://primer.io/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Display detected card network

> Show the card brand logo as users type their card number.

Display the detected card network (Visa, Mastercard, etc.) as users enter their card number.

## Recipe

<Tabs>
  <Tab title="Web">
    ```javascript theme={"dark"}
    checkout.addEventListener('primer:bin-data-available', (event) => {
      const { preferred, status } = event.detail;

      if (preferred) {
        document.getElementById('card-logo').src = `/images/${preferred.network.toLowerCase()}.svg`;
      }
    });
    ```
  </Tab>

  <Tab title="Android">
    ```kotlin theme={"dark"}
    val controller = rememberCardFormController(checkout)
    val state by controller.state.collectAsStateWithLifecycle()

    val detected = state.networkSelection.selectedNetwork

    if (detected != null) {
        Text(text = detected.displayName)
    }
    ```

    <Info>
      `PrimerCardForm` displays the card brand icon automatically in the card number field. Custom rendering is optional -- use `state.networkSelection` only if you need to display the network outside the card form.
    </Info>
  </Tab>

  <Tab title="iOS">
    ```swift theme={"dark"}
    struct CardFormWithNetwork: View {
      let scope: any PrimerCardFormScope
      @State private var selectedNetwork: PrimerCardNetwork?

      var body: some View {
        HStack {
          scope.PrimerCardNumberField(label: "Card number", styling: nil)
          if let network = selectedNetwork {
            Text(network.rawValue)
              .font(.caption)
              .padding(4)
              .background(Color(.secondarySystemBackground))
              .cornerRadius(4)
          }
        }
        .task {
          for await state in scope.state {
            selectedNetwork = state.selectedNetwork
          }
        }
      }
    }
    ```

    <Info>
      The card form fields handle network detection automatically. Use `state.selectedNetwork` only if you need to display the network outside the card form.
    </Info>
  </Tab>
</Tabs>

## How it works

<Tabs>
  <Tab title="Web">
    1. Listen for the `primer:bin-data-available` event
    2. Use `preferred.network` to get the card brand identifier
    3. Update your UI with the appropriate logo or icon
  </Tab>

  <Tab title="Android">
    1. Create a `PrimerCardFormController` using `rememberCardFormController()`
    2. Observe its `state` with `collectAsStateWithLifecycle()`
    3. Read `state.networkSelection.selectedNetwork` for the currently detected network
    4. The state updates reactively as the user types -- no event listener needed

    | Property              | Type                      | Description                                   |
    | --------------------- | ------------------------- | --------------------------------------------- |
    | `selectedNetwork`     | `PrimerCardNetwork?`      | Currently detected network, or `null`         |
    | `availableNetworks`   | `List<PrimerCardNetwork>` | All selectable networks (for co-badged cards) |
    | `isNetworkSelectable` | `Boolean`                 | `true` when the card has multiple networks    |
  </Tab>

  <Tab title="iOS">
    1. Observe `scope.state` using `for await` in a `.task` modifier
    2. Read `state.selectedNetwork` for the currently detected network
    3. Read `state.availableNetworks` for all selectable networks (co-badged cards)
    4. The state updates reactively as the user types

    | Property            | Type                  | Description                                   |
    | ------------------- | --------------------- | --------------------------------------------- |
    | `selectedNetwork`   | `PrimerCardNetwork?`  | Currently detected network, or `nil`          |
    | `availableNetworks` | `[PrimerCardNetwork]` | All selectable networks (for co-badged cards) |
  </Tab>
</Tabs>

The `preferred` field contains the recommended card network based on `orderedAllowedCardNetworks`. It is `undefined` when no network is detected (e.g., empty input or insufficient digits).

## The preferred object

<Tabs>
  <Tab title="Web">
    The `preferred` object contains the detected card network and, when `status` is `'complete'`, additional issuer details:

    ```typescript theme={"dark"}
    {
      displayName: string;  // Human-readable name (e.g., "Visa", "American Express")
      network: string;      // Backend identifier (e.g., "VISA", "AMEX")
      allowed: boolean;     // Whether the network is allowed per orderedAllowedCardNetworks
      // Available when status is 'complete':
      issuerCountryCode?: string;
      issuerName?: string;
      accountFundingType?: string;
    }
    ```

    <Info>
      See the [Events Reference](/sdk/primer-checkout-web/events-reference#bindatadetails) for the full `BinDataDetails` type definition.
    </Info>
  </Tab>

  <Tab title="Android">
    ```kotlin theme={"dark"}
    data class PrimerCardNetwork(
        val network: CardNetwork.Type,
        val displayName: String,
        val allowed: Boolean,
    )
    ```

    `selectedNetwork` is `null` when no card network is detected. Android uses the `CardNetwork.Type` enum with a `displayName` property.
  </Tab>

  <Tab title="iOS">
    ```swift theme={"dark"}
    enum PrimerCardNetwork: String {
        case visa, masterCard, amex, discover, jcb, maestro, ...
    }
    ```

    `selectedNetwork` is `nil` when no card network is detected. iOS uses the `PrimerCardNetwork` enum with a `rawValue` string property.
  </Tab>
</Tabs>

## Supported card networks

| `network`          | `displayName`    |
| ------------------ | ---------------- |
| `VISA`             | Visa             |
| `MASTERCARD`       | Mastercard       |
| `AMEX`             | American Express |
| `DISCOVER`         | Discover         |
| `DINERS_CLUB`      | Diners Club      |
| `JCB`              | JCB              |
| `MAESTRO`          | Maestro          |
| `UNIONPAY`         | UnionPay         |
| `ELO`              | Elo              |
| `HIPER`            | Hiper            |
| `HIPERCARD`        | Hipercard        |
| `MIR`              | Mir              |
| `CARTES_BANCAIRES` | Cartes Bancaires |
| `DANKORT`          | Dankort          |
| `EFTPOS`           | Eftpos           |
| `OTHER`            | Other            |

<Info>
  On Android, these are values of the `CardNetwork.Type` enum. Each value has a `displayName` property matching the table above.
</Info>

## Variations

### Show a loading indicator

Use `primer:bin-data-loading-change` to indicate when BIN data is being fetched:

```javascript theme={"dark"}
checkout.addEventListener('primer:bin-data-loading-change', (event) => {
  const { loading } = event.detail;
  document.getElementById('card-logo').style.opacity = loading ? '0.5' : '1';
});
```

### Display card network name

<Tabs>
  <Tab title="Web">
    For user-facing text, use `displayName` instead of `network`:

    ```javascript theme={"dark"}
    checkout.addEventListener('primer:bin-data-available', (event) => {
      const { preferred } = event.detail;

      const networkName = preferred?.displayName || 'Card';
      document.getElementById('card-type-label').textContent = networkName;
    });
    ```
  </Tab>

  <Tab title="Android">
    ```kotlin theme={"dark"}
    val controller = rememberCardFormController(checkout)
    val state by controller.state.collectAsStateWithLifecycle()

    val networkName = state.networkSelection.selectedNetwork?.displayName ?: "Card"
    Text(text = "Paying with $networkName")
    ```
  </Tab>

  <Tab title="iOS">
    ```swift theme={"dark"}
    if let network = selectedNetwork {
      Text("Paying with \(network.rawValue)")
    } else {
      Text("Paying with Card")
    }
    ```
  </Tab>
</Tabs>

### Show/hide based on detection

<Tabs>
  <Tab title="Web">
    ```javascript theme={"dark"}
    const cardLogo = document.getElementById('card-logo');

    checkout.addEventListener('primer:bin-data-available', (event) => {
      const { preferred } = event.detail;

      if (preferred) {
        cardLogo.src = `/images/${preferred.network.toLowerCase()}.svg`;
        cardLogo.style.display = 'block';
      } else {
        cardLogo.style.display = 'none';
      }
    });
    ```
  </Tab>

  <Tab title="Android">
    ```kotlin theme={"dark"}
    val controller = rememberCardFormController(checkout)
    val state by controller.state.collectAsStateWithLifecycle()

    val detected = state.networkSelection.selectedNetwork

    AnimatedVisibility(visible = detected != null) {
        if (detected != null) {
            Text(text = detected.displayName)
        }
    }
    ```
  </Tab>

  <Tab title="iOS">
    ```swift theme={"dark"}
    @State private var selectedNetwork: PrimerCardNetwork?

    var body: some View {
      VStack {
        if let network = selectedNetwork {
          Text(network.rawValue)
            .transition(.opacity)
        }
        scope.PrimerCardNumberField(label: "Card number", styling: nil)
      }
      .animation(.default, value: selectedNetwork)
      .task {
        for await state in scope.state {
          selectedNetwork = state.selectedNetwork
        }
      }
    }
    ```
  </Tab>
</Tabs>

### Co-badge network selector

<Tabs>
  <Tab title="Web">
    Some cards support multiple networks (e.g., Carte Bancaire / Visa). Use `alternatives` to offer a network picker:

    ```javascript theme={"dark"}
    checkout.addEventListener('primer:bin-data-available', (event) => {
      const { preferred, alternatives } = event.detail;
      const cobrandEl = document.getElementById('cobrand-selector');

      if (preferred) {
        document.getElementById('card-logo').src = `/images/${preferred.network.toLowerCase()}.svg`;
      }

      const selectableNetworks = [preferred, ...alternatives].filter(n => n?.allowed);
      cobrandEl.hidden = selectableNetworks.length <= 1;
    });
    ```
  </Tab>

  <Tab title="Android">
    ```kotlin theme={"dark"}
    val controller = rememberCardFormController(checkout)
    val state by controller.state.collectAsStateWithLifecycle()
    val networkSelection = state.networkSelection

    if (networkSelection.isNetworkSelectable && networkSelection.availableNetworks.size > 1) {
        NetworkSelector(
            networks = networkSelection.availableNetworks,
            selected = networkSelection.selectedNetwork,
            onSelect = { network -> controller.selectCardNetwork(network) },
        )
    }
    ```

    <Info>
      `PrimerCardForm` renders a dropdown selector for co-badged cards automatically. Use `selectCardNetwork()` only if building a fully custom card form.
    </Info>
  </Tab>

  <Tab title="iOS">
    When a card supports multiple networks, `availableNetworks` contains all options. Use the `cobadgedCardsView` property to provide a custom network selector:

    ```swift theme={"dark"}
    cardScope.cobadgedCardsView = { networks, onSelect in
      AnyView(
        HStack {
          ForEach(networks, id: \.self) { network in
            Button(network) {
              onSelect(network)
            }
            .buttonStyle(.bordered)
          }
        }
      )
    }
    ```

    <Info>
      The SDK renders a default co-badge selector automatically. Use `cobadgedCardsView` only if you need a fully custom selector.
    </Info>
  </Tab>
</Tabs>

### Use icon font or CSS classes

```javascript theme={"dark"}
checkout.addEventListener('primer:bin-data-available', (event) => {
  const { preferred } = event.detail;
  const iconEl = document.getElementById('card-icon');

  if (preferred) {
    iconEl.classList.add(`card-${preferred.network.toLowerCase()}`);
  }
});
```

## See also

<CardGroup cols={2}>
  <Card title="Build a custom card form" icon="credit-card" href="/checkout/primer-checkout/guides-and-recipes/build-custom-card-form">
    Step-by-step guide to building a fully custom card form
  </Card>

  <Card title="Events guide" icon="bolt" href="/checkout/primer-checkout/configuration/events">
    Handle payment lifecycle events
  </Card>

  <Card title="Use BIN data for Click to Pay" icon="bolt" href="/checkout/primer-checkout/guides-and-recipes/use-bin-data-to-control-click-to-pay">
    Control Click to Pay based on BIN data
  </Card>
</CardGroup>
