Back to Blog
3 min read

Business Card Reader with AI Builder: Digitizing Contact Information

The AI Builder business card reader extracts contact information from business cards automatically. It’s perfect for sales teams, event attendees, and anyone who needs to quickly digitize networking contacts.

Extracted Fields

business_card_fields:
  name:
    - FirstName
    - LastName
    - FullName
    - CleanedName

  contact:
    - Email
    - Phone
    - MobilePhone
    - Fax

  address:
    - Address
    - City
    - State
    - PostalCode
    - Country

  professional:
    - CompanyName
    - Department
    - JobTitle
    - Website

Power Apps Implementation

// Camera screen for card capture
CameraControl.StreamRate = 100

CaptureButton.OnSelect =
    Set(CardImage, Camera1.Photo);
    Set(ProcessingCard, true);
    Set(
        CardData,
        AIBuilder.BusinessCardReader(CardImage)
    );
    Set(ProcessingCard, false);
    Navigate(ReviewContactScreen);

// Review screen
FirstNameInput.Default = CardData.FirstName
LastNameInput.Default = CardData.LastName
EmailInput.Default = CardData.Email
PhoneInput.Default = CardData.Phone
CompanyInput.Default = CardData.CompanyName
TitleInput.Default = CardData.JobTitle

// Confidence indicators
EmailConfidence.Fill = If(
    CardData.EmailConfidence > 0.9, Color.Green,
    CardData.EmailConfidence > 0.7, Color.Orange,
    Color.Red
)

// Save to contacts
SaveButton.OnSelect =
    // Check for duplicates
    If(
        CountRows(
            Filter(Contacts, Email = EmailInput.Text)
        ) > 0,
        Notify("Contact with this email already exists", NotificationType.Warning);
        Set(DuplicateContact, LookUp(Contacts, Email = EmailInput.Text)),

        // Create new contact
        Patch(
            Contacts,
            Defaults(Contacts),
            {
                FirstName: FirstNameInput.Text,
                LastName: LastNameInput.Text,
                Email: EmailInput.Text,
                Phone: PhoneInput.Text,
                MobilePhone: MobileInput.Text,
                Company: CompanyInput.Text,
                JobTitle: TitleInput.Text,
                Address: AddressInput.Text,
                Website: WebsiteInput.Text,
                BusinessCardImage: CardImage,
                Source: "Business Card Scan",
                ScannedDate: Now(),
                ScannedBy: User().Email
            }
        );
        Notify("Contact saved successfully!", NotificationType.Success);
        Navigate(HomeScreen)
    )

Dataverse Integration

{
    "actions": {
        "Process_Business_Card": {
            "type": "AIBuilder",
            "inputs": {
                "model": "prebuilt-businessCardReader",
                "document": "@{triggerBody()?['cardImage']}"
            }
        },
        "Check_Existing_Contact": {
            "type": "ListRecords",
            "inputs": {
                "table": "contacts",
                "filter": "emailaddress1 eq '@{body('Process_Business_Card')?['results']?['Email']?['value']}'"
            }
        },
        "Create_Or_Update_Contact": {
            "type": "Condition",
            "expression": {
                "equals": ["@length(body('Check_Existing_Contact')?['value'])", 0]
            },
            "actions": {
                "Create_Contact": {
                    "type": "CreateRecord",
                    "inputs": {
                        "table": "contacts",
                        "item": {
                            "firstname": "@{body('Process_Business_Card')?['results']?['FirstName']?['value']}",
                            "lastname": "@{body('Process_Business_Card')?['results']?['LastName']?['value']}",
                            "emailaddress1": "@{body('Process_Business_Card')?['results']?['Email']?['value']}",
                            "telephone1": "@{body('Process_Business_Card')?['results']?['Phone']?['value']}",
                            "mobilephone": "@{body('Process_Business_Card')?['results']?['MobilePhone']?['value']}",
                            "jobtitle": "@{body('Process_Business_Card')?['results']?['JobTitle']?['value']}",
                            "address1_composite": "@{body('Process_Business_Card')?['results']?['Address']?['value']}",
                            "websiteurl": "@{body('Process_Business_Card')?['results']?['Website']?['value']}"
                        }
                    }
                },
                "Link_To_Account": {
                    "type": "Condition",
                    "expression": {
                        "not": ["@empty(body('Process_Business_Card')?['results']?['CompanyName']?['value'])"]
                    },
                    "actions": {
                        "Find_Or_Create_Account": {
                            "type": "Compose"
                        }
                    }
                }
            },
            "else": {
                "actions": {
                    "Update_Existing_Contact": {
                        "type": "UpdateRecord",
                        "inputs": {
                            "table": "contacts",
                            "id": "@{first(body('Check_Existing_Contact')?['value'])?['contactid']}",
                            "item": {
                                "telephone1": "@{coalesce(body('Process_Business_Card')?['results']?['Phone']?['value'], first(body('Check_Existing_Contact')?['value'])?['telephone1'])}",
                                "jobtitle": "@{body('Process_Business_Card')?['results']?['JobTitle']?['value']}"
                            }
                        }
                    }
                }
            }
        }
    }
}

Event Lead Capture

// Event lead capture app
Screen: EventLeadCapture

// Event selection
EventDropdown.Items = Filter(Events, EndDate >= Today())

// Quick capture mode
QuickCaptureToggle.OnCheck =
    Set(QuickMode, true);
    Set(AutoSave, true);

// Capture and process
CaptureCardBtn.OnSelect =
    Set(CardPhoto, Camera1.Photo);
    Set(
        ExtractedData,
        AIBuilder.BusinessCardReader(CardPhoto)
    );

    If(
        QuickMode,
        // Auto-save in quick mode
        Patch(
            EventLeads,
            Defaults(EventLeads),
            {
                Event: EventDropdown.Selected,
                FirstName: ExtractedData.FirstName,
                LastName: ExtractedData.LastName,
                Email: ExtractedData.Email,
                Phone: ExtractedData.Phone,
                Company: ExtractedData.CompanyName,
                Title: ExtractedData.JobTitle,
                CardImage: CardPhoto,
                CapturedBy: User().Email,
                CapturedAt: Now(),
                Notes: "",
                FollowUpRequired: false
            }
        );
        Notify("Lead captured!", NotificationType.Success),

        // Show review form in standard mode
        Navigate(ReviewLeadScreen)
    );

// Add notes to lead
NotesInput.OnChange =
    If(
        Len(NotesInput.Text) > 0,
        UpdateContext({HasNotes: true})
    );

// Mark for follow-up
FollowUpToggle.OnCheck =
    UpdateContext({RequiresFollowUp: true});

// Batch export
ExportLeadsBtn.OnSelect =
    Set(
        LeadExport,
        Filter(EventLeads, Event.ID = EventDropdown.Selected.ID)
    );
    // Export to Excel or send to CRM

Best Practices

scanning_tips:
  card_positioning:
    - Place card on contrasting background
    - Ensure all edges visible
    - Avoid shadows
    - Keep camera parallel to card

  lighting:
    - Even, diffused lighting
    - Avoid direct flash
    - No glare on glossy cards

  card_types:
    supported:
      - Standard business cards
      - Vertical cards
      - Multi-language cards
    challenging:
      - Very dark backgrounds
      - Unusual fonts
      - Handwritten additions

Conclusion

The business card reader streamlines contact digitization:

  • Instant extraction of contact details
  • Integration with CRM systems
  • Perfect for events and networking
  • Reduces manual data entry errors

Resources

Michael John Peña

Michael John Peña

Senior Data Engineer based in Sydney. Writing about data, cloud, and technology.