checkout.addEventListener('primer:bin-data-available', (event) => { const { preferred, status } = event.detail; if (preferred) { document.getElementById('card-logo').src = `/images/${preferred.network.toLowerCase()}.svg`; }});
val controller = rememberCardFormController(checkout)val state by controller.state.collectAsStateWithLifecycle()val detected = state.networkSelection.selectedNetworkif (detected != null) { Text(text = detected.displayName)}
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.
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 { VStack(alignment: .leading) { if let network = session.state.selectedNetwork { Text(network.displayName) .font(.caption) .padding(4) .background(Color(.secondarySystemBackground)) .cornerRadius(4) } CardFormDefaults.cardDetails(session) } }}
PrimerCardForm displays the card brand icon automatically in the card number field. Read session.state.selectedNetwork only if you need to display the network outside the card form. It holds the network the form uses, and it is nil until a network is detected from the card number. For a co-badged card, it is the first entry of availableNetworks until the user picks another one.
Use preferred.network to get the card brand identifier
Update your UI with the appropriate logo or icon
Create a PrimerCardFormController using rememberCardFormController()
Observe its state with collectAsStateWithLifecycle()
Read state.networkSelection.selectedNetwork for the currently detected network
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
Mark the PrimerCardFormSession injected into your slot closure as @ObservedObject
Read session.state.selectedNetwork for the network the form uses; it is nil until a network is detected from the card number
Read session.state.availableNetworks for the detected networks your orderedAllowedCardNetworks allows, in that order; more than one indicates a co-badged card
The state updates reactively as the user types — no event listener needed
Property
Type
Description
availableNetworks
[PrimerCardNetwork]
Detected networks that your orderedAllowedCardNetworks allows, in that order, or the first detected network if none is allowed. More than one indicates a co-badged card.
selectedNetwork
PrimerCardNetwork?
Network the form uses: the detected network, or the user’s pick for a co-badged card. nil until a network is detected
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 contains the detected card network and, when status is 'complete', additional issuer details:
{ 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;}
See the Events Reference for the full BinDataDetails type definition.
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.
@objcpublic final class PrimerCardNetwork: NSObject { public let displayName: String // Human-readable name (e.g. "Visa") public let network: CardNetwork // String-backed enum (.visa, .masterCard, ...) public var allowed: Bool { get } // In the client session's orderedAllowedCardNetworks public var allowsUserSelection: Bool { get } // false for networks that auto-route (EFTPOS) // Issuer details: set only on `binData` entries, `nil` elsewhere public let issuerCountryCode: String? public let issuerName: String? public let accountFundingType: String? public let prepaidReloadableIndicator: String? public let productUsageType: String? public let productCode: String? public let productName: String? public let issuerCurrencyCode: String? public let regionalRestriction: String? public let accountNumberType: String?}
The network the form uses comes from selectedNetwork; it is nil until a network is detected from the card number. availableNetworks lists the detected networks that your orderedAllowedCardNetworks allows, in that order (more than one for a co-badged card). If none is allowed, it holds only the first detected network. It is empty when no card network is detected. To also see detected networks that are not allowed, read binData.alternatives. iOS exposes PrimerCardNetwork with a displayName string property and a network (CardNetwork) enum whose raw value matches the backend identifier (e.g. "VISA").For issuer details, read session.state.binData. It is a PrimerBinData? that is nil until the first detection, with four properties:
preferred: PrimerCardNetwork? is the first allowed network in your orderedAllowedCardNetworks order. It is nil when no detected network is allowed or no card number is entered.
alternatives: [PrimerCardNetwork] lists the other detected networks in the same order.
status: PrimerBinDataStatus is .partial while the network is detected locally from the card number. This happens with fewer than 8 digits, or when the remote lookup fails. It is .complete after the remote BIN lookup.
firstDigits: String? is set for .complete results and is nil for .partial results.
The PrimerCardNetwork entries in preferred and alternatives carry the issuer details as optional properties. These are issuerCountryCode, issuerName, accountFundingType, prepaidReloadableIndicator, productUsageType, productCode, productName, issuerCurrencyCode, regionalRestriction and accountNumberType. They are nil for .partial results and for any value the lookup does not return. The entries in availableNetworks and selectedNetwork never carry issuer details.
if let bin = session.state.binData, bin.status == .complete { Text(bin.preferred?.issuerName ?? "")}
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 for the authoritative iOS list.
val controller = rememberCardFormController(checkout)val state by controller.state.collectAsStateWithLifecycle()val networkName = state.networkSelection.selectedNetwork?.displayName ?: "Card"Text(text = "Paying with $networkName")
let networkName = session.state.selectedNetwork?.displayName ?? "Card"Text("Paying with \(networkName)")
PrimerCardForm renders a dropdown selector for co-badged cards automatically. Use selectCardNetwork() only if building a fully custom card form.
When a card supports multiple networks, session.state.availableNetworks contains all options. Render your own picker and commit the choice with session.selectCardNetwork(_:). After that call, session.state.selectedNetwork holds the user’s pick:
@ObservedObject var session: PrimerCardFormSessionvar 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) } } }}
PrimerCardForm renders a network selector for co-badged cards automatically, inside the card number field. It is a dropdown by default. With PrimerCardPaymentOptions(networkSelectorStyle: .inline), it shows inline badges instead. When a detected network such as EFTPOS does not allow selection, it shows the badges of all detected networks and offers no choice. CardFormDefaults.cardNumber(session) keeps this selector when you recompose the fields, so do not add CardFormDefaults.cardNetwork(session) next to it. Call selectCardNetwork(_:) only when you build your own picker.