Skip to main content
RapidDev - Software Development Agency
flutterflow-tutorials

How to Use NFC for Payments and Event Check-ins in FlutterFlow

FlutterFlow apps use the nfc_manager package (added after code export) to read and write NFC tags for event check-ins and product lookups. For contactless payments, use the pay package to display Apple Pay and Google Pay sheets — actual payment processing still runs through Stripe on the server. Note: iOS supports NFC reading only; Android supports both reading and writing NFC tags.

What you'll learn

  • How to read NFC tags for event check-in and product information using the nfc_manager package
  • How to write data to NFC tags on Android for event badges and access passes
  • How to display Apple Pay and Google Pay sheets using the pay package
  • The platform limitations of NFC on iOS versus Android
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Beginner11 min read45-60 minFlutterFlow Pro+ (code export required for nfc_manager and pay packages)March 2026RapidDev Engineering Team
TL;DR

FlutterFlow apps use the nfc_manager package (added after code export) to read and write NFC tags for event check-ins and product lookups. For contactless payments, use the pay package to display Apple Pay and Google Pay sheets — actual payment processing still runs through Stripe on the server. Note: iOS supports NFC reading only; Android supports both reading and writing NFC tags.

NFC in Flutter: Reading Tags and Triggering Payments

Near-field communication enables your app to interact with physical NFC tags embedded in event badges, product labels, and access cards. In FlutterFlow, NFC is implemented through Custom Actions added after code export. The nfc_manager package handles tag detection and reading on both iOS and Android, plus writing on Android. For payments, the pay package renders native Apple Pay and Google Pay sheets — the actual charge is processed by your Stripe Cloud Function after the user approves in the native UI. This tutorial covers both workflows: NFC check-in for events and NFC-triggered payments.

Prerequisites

  • A FlutterFlow Pro account with code export enabled
  • An Apple Developer account with NFC entitlement enabled for iOS ($99/year)
  • A Firebase project with Firestore and Authentication configured
  • A Stripe account with Apple Pay and Google Pay domains verified
  • A physical NFC-enabled Android or iPhone (XS or later for iOS background scanning)

Step-by-step guide

1

Add NFC and pay packages after exporting the project

Export your FlutterFlow project to a local Flutter project. Open pubspec.yaml and add two packages: nfc_manager (version ^3.3.0) for NFC tag interaction, and pay (version ^2.0.0) for native payment sheets. Run flutter pub get. For iOS, open ios/Runner.xcworkspace in Xcode, go to Runner → Signing & Capabilities, click '+' and add the 'Near Field Communication Tag Reading' capability. Then open ios/Runner/Info.plist and add the NFCReaderUsageDescription key with a user-facing explanation like 'This app uses NFC to scan event badges and product tags.' For Android, add the NFC permission to android/app/src/main/AndroidManifest.xml.

pubspec.yaml
1# pubspec.yaml additions
2dependencies:
3 nfc_manager: ^3.3.0
4 pay: ^2.0.0
5
6# ios/Runner/Info.plist add inside <dict>:
7# <key>NFCReaderUsageDescription</key>
8# <string>Scan event badges and product NFC tags</string>
9
10# android/app/src/main/AndroidManifest.xml add inside <manifest>:
11# <uses-permission android:name="android.permission.NFC" />
12# <uses-feature android:name="android.hardware.nfc" android:required="false" />

Expected result: flutter pub get succeeds. On iOS, the NFC entitlement appears in Xcode. The app builds without errors on both platforms.

2

Create a Custom Action to read an NFC tag

In your exported Flutter project, create a file at lib/custom_actions/read_nfc_tag.dart. The action starts an NFC session, waits for a tag, reads the NDEF records from the tag, and returns the first text record as a String. On iOS, the session shows a native 'Ready to scan' sheet automatically. On Android, you need to show your own scanning UI (a dialog or bottom sheet) while the session is active. The returned String is the tag's payload — for an event badge it might be an attendee ID like 'attendee:abc123', which you then look up in Firestore.

lib/custom_actions/read_nfc_tag.dart
1// lib/custom_actions/read_nfc_tag.dart
2import 'package:nfc_manager/nfc_manager.dart';
3
4Future<String?> readNfcTag() async {
5 bool isAvailable = await NfcManager.instance.isAvailable();
6 if (!isAvailable) return null;
7
8 String? result;
9 await NfcManager.instance.startSession(
10 onDiscovered: (NfcTag tag) async {
11 final ndef = Ndef.from(tag);
12 if (ndef == null) {
13 await NfcManager.instance.stopSession(errorMessage: 'Tag not NDEF formatted');
14 return;
15 }
16 final message = ndef.cachedMessage;
17 if (message == null || message.records.isEmpty) {
18 await NfcManager.instance.stopSession(errorMessage: 'No data on tag');
19 return;
20 }
21 final record = message.records.first;
22 // Decode text payload (skip language code bytes)
23 final payload = record.payload;
24 final languageCodeLength = payload[0] & 0x3F;
25 result = String.fromCharCodes(
26 payload.sublist(1 + languageCodeLength));
27 await NfcManager.instance.stopSession();
28 },
29 );
30 return result;
31}

Expected result: Tapping the 'Scan Badge' button starts an NFC session. Holding an NFC badge to the phone returns the tag's text payload as a String you can use in your FlutterFlow action flow.

3

Implement event check-in with Firestore validation

In FlutterFlow's Action Flow editor, create the check-in flow for your event scanner page. The flow is: 1) Call the readNfcTag Custom Action and store the result in a Page State variable called 'scannedPayload'. 2) Check if scannedPayload starts with 'attendee:' — if not, show a 'Invalid badge' snackbar. 3) Extract the attendee ID (substring after 'attendee:'). 4) Query the Firestore 'attendees' collection where document ID equals the attendee ID. 5) If the document has checked_in set to true, show 'Already checked in'. 6) If not, update the document with checked_in: true and checked_in_at: current timestamp. 7) Show a success snackbar with the attendee's name. The entire flow from scan to confirmation takes under 2 seconds.

Expected result: Scanning a valid event badge marks the attendee as checked in and shows their name. Scanning an already-checked-in badge shows an informative message instead of allowing re-entry.

4

Write data to NFC tags on Android

Create a Custom Action called 'writeNfcTag' that accepts a String payload parameter. The action formats the payload as an NDEF text record and writes it to a presented NFC tag. This is useful for printing event badges: write the attendee ID format to a blank NFC sticker, then stick it on the badge. iOS does not support NFC writing from third-party apps, so add a platform check using Platform.isAndroid and show an alert on iOS explaining that tag writing requires Android. Provide a fallback QR code workflow for iOS check-in staff.

lib/custom_actions/write_nfc_tag.dart
1// lib/custom_actions/write_nfc_tag.dart
2import 'dart:io';
3import 'package:nfc_manager/nfc_manager.dart';
4
5Future<bool> writeNfcTag(String payload) async {
6 if (!Platform.isAndroid) {
7 // iOS does not support third-party NFC writing
8 return false;
9 }
10 bool isAvailable = await NfcManager.instance.isAvailable();
11 if (!isAvailable) return false;
12
13 bool success = false;
14 await NfcManager.instance.startSession(
15 onDiscovered: (NfcTag tag) async {
16 final ndef = Ndef.from(tag);
17 if (ndef == null || !ndef.isWritable) {
18 await NfcManager.instance.stopSession(
19 errorMessage: 'Tag is not writable');
20 return;
21 }
22 try {
23 await ndef.write(NdefMessage([
24 NdefRecord.createText(payload),
25 ]));
26 success = true;
27 await NfcManager.instance.stopSession();
28 } catch (e) {
29 await NfcManager.instance.stopSession(errorMessage: e.toString());
30 }
31 },
32 );
33 return success;
34}

Expected result: On Android, presenting a blank NFC sticker writes the payload to it. The sticker can then be read by both iOS and Android devices using the readNfcTag action.

5

Add Apple Pay and Google Pay using the pay package

For NFC-triggered payments (e.g., tap a product tag to buy it), use the pay package to show native payment sheets. In your Custom Action, create a PaymentConfiguration from a JSON string that includes your payment provider details. When a product NFC tag is scanned and the user taps 'Buy with Apple Pay' or 'Pay with Google Pay', call the payment sheet Custom Action passing the amount and item name. On payment success, the action returns a payment result token — send this to your Stripe Cloud Function to capture the actual charge. Never process payments purely client-side.

lib/custom_actions/show_payment_sheet.dart
1// lib/custom_actions/show_payment_sheet.dart
2import 'package:pay/pay.dart';
3import 'dart:convert';
4
5Future<String?> showPaymentSheet(String itemName, double amount) async {
6 final paymentItems = [PaymentItem(label: itemName, amount: amount.toStringAsFixed(2))];
7
8 // Apple Pay configuration
9 final applePayConfig = PaymentConfiguration.fromJsonString(jsonEncode({
10 'provider': 'apple_pay',
11 'data': {
12 'merchantIdentifier': 'merchant.com.yourapp',
13 'displayName': 'Your App',
14 'merchantCapabilities': ['3DS', 'debit', 'credit'],
15 'supportedNetworks': ['amex', 'visa', 'masterCard'],
16 'countryCode': 'US',
17 'currencyCode': 'USD',
18 }
19 }));
20
21 try {
22 final result = await Pay.withAssets(['apple_pay.json']).showPaymentSelector(
23 PayProvider.apple_pay,
24 paymentItems,
25 );
26 // result contains the payment token — send to your backend
27 return jsonEncode(result);
28 } catch (e) {
29 return null;
30 }
31}

Expected result: Tapping 'Pay' after scanning a product NFC tag shows the native Apple Pay or Google Pay sheet pre-filled with the item name and price.

Complete working example

lib/custom_actions/nfc_manager_utils.dart
1// nfc_manager_utils.dart — Shared NFC utilities for FlutterFlow custom actions
2// Handles availability check, NDEF read, write, and platform detection
3
4import 'dart:io';
5import 'dart:typed_data';
6import 'package:nfc_manager/nfc_manager.dart';
7
8/// Check if NFC is available on this device
9Future<bool> isNfcAvailable() async {
10 return await NfcManager.instance.isAvailable();
11}
12
13/// Read an NDEF text record from an NFC tag
14/// Returns the text payload, or null if unavailable/error
15Future<String?> readNfcTag() async {
16 if (!await isNfcAvailable()) return null;
17
18 String? result;
19 await NfcManager.instance.startSession(
20 onDiscovered: (NfcTag tag) async {
21 final ndef = Ndef.from(tag);
22 if (ndef == null) {
23 await NfcManager.instance
24 .stopSession(errorMessage: 'Tag not NDEF formatted');
25 return;
26 }
27 final message = ndef.cachedMessage;
28 if (message == null || message.records.isEmpty) {
29 await NfcManager.instance
30 .stopSession(errorMessage: 'No NDEF records found');
31 return;
32 }
33 final record = message.records.first;
34 final payload = record.payload;
35 if (payload.isEmpty) {
36 await NfcManager.instance.stopSession(errorMessage: 'Empty payload');
37 return;
38 }
39 // NDEF Text record: first byte is status byte
40 // bits 0-5: language code length
41 final languageCodeLength = payload[0] & 0x3F;
42 result = String.fromCharCodes(
43 payload.sublist(1 + languageCodeLength));
44 await NfcManager.instance.stopSession();
45 },
46 );
47 return result;
48}
49
50/// Write an NDEF text record to an NFC tag (Android only)
51/// Returns true on success, false on failure or iOS
52Future<bool> writeNfcTag(String payload) async {
53 if (Platform.isIOS) return false; // iOS does not support third-party writing
54 if (!await isNfcAvailable()) return false;
55
56 bool success = false;
57 await NfcManager.instance.startSession(
58 onDiscovered: (NfcTag tag) async {
59 final ndef = Ndef.from(tag);
60 if (ndef == null || !ndef.isWritable) {
61 await NfcManager.instance
62 .stopSession(errorMessage: 'Tag not writable');
63 return;
64 }
65 try {
66 final message = NdefMessage([NdefRecord.createText(payload)]);
67 // Check capacity before writing
68 if (ndef.maxSize < message.byteLength) {
69 await NfcManager.instance
70 .stopSession(errorMessage: 'Tag too small for this payload');
71 return;
72 }
73 await ndef.write(message);
74 success = true;
75 await NfcManager.instance.stopSession();
76 } catch (e) {
77 await NfcManager.instance.stopSession(errorMessage: e.toString());
78 }
79 },
80 );
81 return success;
82}
83
84/// Parse the attendee ID from an NFC badge payload
85/// Expected format: 'attendee:abc123'
86String? parseAttendeeId(String payload) {
87 if (!payload.startsWith('attendee:')) return null;
88 return payload.substring('attendee:'.length);
89}
90
91/// Parse the product SKU from a product NFC payload
92/// Expected format: 'product:SKU123'
93String? parseProductSku(String payload) {
94 if (!payload.startsWith('product:')) return null;
95 return payload.substring('product:'.length);
96}

Common mistakes

Why it's a problem: Expecting NFC to work in FlutterFlow's web preview or Run Mode

How to avoid: Always test NFC features on a physical device using flutter run after exporting the project. Use a conditional in the UI to detect NFC availability and show an appropriate message on unsupported devices.

Why it's a problem: Assuming iOS supports NFC tag writing

How to avoid: Add a Platform.isIOS check in your write action and return false immediately. For iOS check-in workflows, provide a QR code scanner fallback since the camera API works on all platforms.

Why it's a problem: Processing the Apple Pay or Google Pay token entirely on the client side

How to avoid: Send the payment token to a Firebase Cloud Function that calls the Stripe API. Never trust the amount from the client — re-read it from Firestore on the server.

Best practices

  • Always check NfcManager.instance.isAvailable() before showing NFC UI — hide NFC options on devices without NFC hardware.
  • Prefix your NFC tag payloads with a namespace (e.g., 'attendee:', 'product:') so your app can validate tags and reject unrelated tags.
  • Add a timeout to NFC sessions — if no tag is detected within 30 seconds, stop the session automatically to preserve battery.
  • For event check-in at high volume, use a Cloud Function with Firestore transactions to prevent two staff members checking in the same attendee simultaneously.
  • Test NFC writing on multiple tag types (NTAG213, NTAG215, MIFARE Ultralight) since payload capacity varies significantly between tag families.
  • Log all NFC scan events to Firestore with the user ID, tag payload hash, and timestamp for audit trails at security-sensitive venues.
  • Implement offline check-in with a local SQLite cache that syncs to Firestore when connectivity is restored — essential for basement venues with poor signal.

Still stuck?

Copy one of these prompts to get a personalized, step-by-step explanation.

ChatGPT Prompt

I'm building a Flutter event check-in app using the nfc_manager package. Write a Dart function that reads an NFC tag, parses a payload in the format 'attendee:ABC123', queries Firestore to find the attendee document by ID, checks if they are already checked in, and if not, sets checked_in: true and checked_in_at: serverTimestamp(). The function should return a result object with status ('success', 'already_checked_in', 'not_found', 'invalid_tag') and the attendee name.

FlutterFlow Prompt

In my FlutterFlow project I have a page called 'ScannerPage'. I want to add a button called 'Scan Badge' that calls a Custom Action named 'readNfcTag' and stores the result in a Page State String variable called 'scannedPayload'. Then I want to query Firestore for the attendee document matching that payload, and show the attendee name in a Text widget. Walk me through setting up this action flow in FlutterFlow's Action Flow editor.

Frequently asked questions

Does NFC work on all iPhones?

NFC reading is available on iPhone 7 and later. Background NFC tag reading (no button tap required) is available on iPhone XS and later running iOS 14+. NFC writing is not available on any iPhone through third-party apps.

What type of NFC tags should I buy for event badges?

NTAG213 tags are the most widely compatible and cost around $0.10-0.20 each in bulk. They hold up to 137 bytes of NDEF data, which is enough for an attendee ID payload. For longer payloads, use NTAG215 (504 bytes) or NTAG216 (888 bytes).

Can I use NFC for access control (door locks)?

Reading NFC badges to validate access is straightforward with this setup. The actual door unlock requires a separate hardware system (a microcontroller connected to a relay). Your FlutterFlow app can display an unlock button after validating the NFC badge, and the unlock action calls a cloud API that signals the hardware.

Is the pay package a complete payment solution?

No. The pay package only handles displaying the native payment sheet and collecting the payment token from Apple Pay or Google Pay. You still need a backend (Stripe is the standard choice) to actually process the charge using that token.

Will this work after I re-import the project back into FlutterFlow?

FlutterFlow does not support re-importing modified exported code back into the visual editor. The recommended workflow is to maintain custom actions as separate Dart files alongside FlutterFlow, or to keep the exported project as your main codebase and use FlutterFlow only as a visual design reference.

Can I detect what type of NFC tag was scanned (e.g., MIFARE vs NTAG)?

Yes. The NfcTag object has a 'data' map that includes platform-specific tag technology data. On Android, nfcA, mifareUltralight, and ndef are common keys. On iOS, feliCa, iso7816, iso15693, and mifare are available. You can check which keys exist to identify the tag technology.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.