> ## 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 {
      var body: some View {
        PrimerCardForm(cardDetails: { session in
          CardDetailsWithNetwork(session: session)
        })
      }
    }

    struct CardDetailsWithNetwork: View {
      @ObservedObject var session: PrimerCardFormSession

      var body: some View {
        HStack {
          CardFormDefaults.cardNumber(session)
          if let network = session.state.availableNetworks.first {
            Text(network.displayName)
              .font(.caption)
              .padding(4)
              .background(Color(.secondarySystemBackground))
              .cornerRadius(4)
          }
        }
      }
    }
    ```

    <Info>
      `PrimerCardForm` displays the card brand icon automatically in the card number field. Read `session.state.availableNetworks` only if you need to display the network outside the card form. For a single-network card, the detected network is `availableNetworks.first`; `selectedNetwork` is reserved for co-badge selection and stays `nil` while the network is auto-detected.
    </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. Mark the `PrimerCardFormSession` injected into your slot closure as `@ObservedObject`
    2. Read `session.state.availableNetworks` for the detected networks (use `availableNetworks.first` for the single-network case)
    3. Use `session.state.selectedNetwork` only for the co-badge choice (it is `nil` while the network is auto-detected)
    4. The state updates reactively as the user types -- no event listener needed

    | Property            | Type                  | Description                                                                       |
    | ------------------- | --------------------- | --------------------------------------------------------------------------------- |
    | `availableNetworks` | `[PrimerCardNetwork]` | Networks detected from the card number. More than one indicates a co-badged card. |
    | `selectedNetwork`   | `PrimerCardNetwork?`  | Currently selected co-badge network, or `nil` while auto-detected                 |
  </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](/docs/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"}
    @objc
    public final class PrimerCardNetwork: NSObject {
        public let displayName: String   // Human-readable name (e.g. "Visa")
        public let network: CardNetwork  // String-backed enum (.visa, .masterCard, ...)
        public let allowed: Bool         // Enabled for the current merchant configuration
    }
    ```

    The detected network comes from `availableNetworks` (use `availableNetworks.first` for the single-network case); it is empty when no card network is detected. `selectedNetwork` is reserved for the co-badge choice and stays `nil` while the network is auto-detected. iOS exposes `PrimerCardNetwork` with a `displayName` string property and a `network` (`CardNetwork`) enum whose raw value matches the backend identifier (e.g. `"VISA"`).
  </Tab>
</Tabs>

## Supported card networks

| `network`          | Web / Android `displayName` | iOS `displayName`            |
| ------------------ | --------------------------- | ---------------------------- |
| `VISA`             | Visa                        | Visa                         |
| `MASTERCARD`       | Mastercard                  | Mastercard                   |
| `AMEX`             | American Express            | American Express             |
| `DISCOVER`         | Discover                    | Discover                     |
| `DINERS_CLUB`      | Diners Club                 | Diners                       |
| `JCB`              | JCB                         | JCB                          |
| `MAESTRO`          | Maestro                     | Maestro                      |
| `UNIONPAY`         | UnionPay                    | UnionPay                     |
| `ELO`              | Elo                         | Elo                          |
| `HIPER`            | Hiper                       | Hiper                        |
| `HIPERCARD`        | Hipercard                   | Hiper                        |
| `MIR`              | Mir                         | Mir                          |
| `CARTES_BANCAIRES` | Cartes Bancaires            | Cartes Bancaires             |
| `BANCONTACT`       | —                           | Bancontact                   |
| `DANKORT`          | Dankort                     | — (not in iOS `CardNetwork`) |
| `EFTPOS`           | Eftpos                      | EFTPOS                       |
| `OTHER`            | Other                       | Unknown                      |

<Info>
  On Android, these are values of the `CardNetwork.Type` enum, each with a `displayName` property. On iOS, the `network` raw values map to cases of the `CardNetwork` enum; a few display names and the supported set differ (iOS has no `DANKORT` and adds `BANCONTACT`). See [PrimerCardNetwork](/docs/sdk/ios-checkout/v3.0.0-beta/api/common/primer-card-network) for the authoritative iOS list.
</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"}
    let networkName = session.state.availableNetworks.first?.displayName ?? "Card"
    Text("Paying with \(networkName)")
    ```
  </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"}
    @ObservedObject var session: PrimerCardFormSession

    var body: some View {
      VStack {
        if let network = session.state.availableNetworks.first {
          Text(network.displayName)
            .transition(.opacity)
        }
        CardFormDefaults.cardNumber(session)
      }
      .animation(.default, value: session.state.availableNetworks.isEmpty)
    }
    ```
  </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, `session.state.availableNetworks` contains all options. Render your own picker and commit the choice with `session.selectCardNetwork(_:)`:

    ```swift theme={"dark"}
    @ObservedObject var session: PrimerCardFormSession

    var body: some View {
      let networks = session.state.availableNetworks
      if networks.count > 1 {
        HStack {
          ForEach(networks, id: \.network) { network in
            Button(network.displayName) {
              session.selectCardNetwork(network)
            }
            .buttonStyle(.bordered)
            .disabled(!network.allowed)
          }
        }
      }
    }
    ```

    <Info>
      `PrimerCardForm` renders a dropdown selector for co-badged cards automatically. When you recompose the individual card fields yourself, drop in `CardFormDefaults.cardNetwork(session)` for the built-in selector, or call `selectCardNetwork()` directly only if building a fully custom one.
    </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="/docs/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="/docs/checkout/primer-checkout/configuration/events">
    Handle payment lifecycle events
  </Card>

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