> For the complete documentation index, see [llms.txt](https://docs.buildnatively.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.buildnatively.com/natively-platform/features/nfc.md).

# NFC

## What is NFC?

NFC (Near Field Communication) lets your app interact with NFC tags - small chips embedded in cards, stickers, or objects. Your app can read data from NFC tags or write data to them, enabling use cases like contactless check-ins, product authentication, smart packaging, loyalty cards, and more.

{% hint style="warning" %}
Natively supports standard, writable, NDEF-formatted NFC tags - specifically **NFC Forum Type 2 Tags** (including NTAG213, NTAG215, NTAG216, and MIFARE Ultralight) and **NFC Forum Type 5 Tags** (ISO15693 NDEF tags). Natively has directly tested NTAG213, NTAG215, and NTAG216; other NDEF-formatted tags following these standards are expected to work but haven't been individually verified.

**Not supported:** payment cards, access cards, MIFARE Classic cards, DESFire applications, and other proprietary or non-NDEF smart cards.
{% endhint %}

## Prerequisites

{% hint style="success" %}
This feature requires the **Unlimited** or **Lifetime** plan. [See all plans](/getting-started/subscription-plans.md)
{% endhint %}

**iOS only:**

* An [Apple Developer](https://developer.apple.com/account) account.
* Your iOS app is already [published](/natively-platform/app-info/ios-build.md) in the Natively Dashboard.

## App Capabilities Configuration (iOS only)

{% hint style="info" %}
App capabilities define what system-level features your app is allowed to use on iOS. Before Natively can include the NFC feature in your iOS build, the **NFC Tag Reading** capability must be explicitly enabled in your Apple Developer account for your app's Bundle ID.
{% endhint %}

1. Open your [Apple Developer account](https://developer.apple.com/account) and navigate to [Certificates, IDs & Profiles > Identifiers](https://developer.apple.com/account/resources/identifiers/list).
2. Select your app's Bundle ID.
3. Scroll down the **Capabilities** list and enable **NFC Tag Reading.**
4. Click **Save** and confirm.

## Natively Dashboard Setup

{% hint style="info" %}
Before proceeding with the iOS app, make sure you have completed the [App Capabilities Configuration (iOS only)](#app-capabilities-configuration-ios-only) step above.
{% endhint %}

1. Open your Natively app dashboard and navigate to **Features > NFC**.
2. Toggle the feature to **Enabled**.
3. Enter the **Permission Description**.
4. Click **Save**.
5. Rebuild your app(s).

{% hint style="info" %}
The **Permission Description** is the text shown to users when the OS asks them to grant **NFC** access. Explain clearly why your app needs this permission - for example: "This app uses NFC to read and write contactless cards."
{% endhint %}

{% hint style="warning" %}
You must rebuild your app for these changes to take effect.
{% endhint %}

## Implementation

Choose your integration method below: **Bubble.io Plugin** (No-Code), **JavaScript SDK** (Code), or **AI Agents** (for AI-powered editors like Lovable, Base44, and Replit).

### Initialization

{% tabs %}
{% tab title="Bubble.io Plugin" %}
**Check Plugin**

Before starting, verify if the Natively plugin is already installed in your Bubble project.

1. Open your Bubble editor and navigate to the Plugins tab in the left sidebar.
2. **Check Installed Plugins:** Look through your list of installed plugins for "Natively iOS & Android app builder".
   * If it IS installed: Check the version number. If an update is available (e.g., you see a button saying "Update"), click it to ensure you have the latest features and bug fixes.

<figure><img src="https://docs.buildnatively.com/~gitbook/image?url=https%3A%2F%2F3352617162-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F90tV7pYflEQdiAr2VfWu%252Fuploads%252FmfnSUug82IdnxOAoBrak%252Fnatively_app_builder_bubble_plugin_update.png%3Falt%3Dmedia%26token%3Dc193f69f-b03b-4be4-b80b-f34ba37ac212&#x26;width=768&#x26;dpr=3&#x26;quality=100&#x26;sign=a89e4510&#x26;sv=2" alt=""><figcaption></figcaption></figure>

* If it is NOT installed: Click the + Add plugins button, search for "Natively", and click Install.

<figure><img src="https://docs.buildnatively.com/~gitbook/image?url=https%3A%2F%2F3352617162-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F90tV7pYflEQdiAr2VfWu%252Fuploads%252FC5rA42yQHcN1uGKFbzmF%252Fnatively_app_builder_bubble_plugin.png%3Falt%3Dmedia%26token%3Dd9706d9b-dbe8-459b-b9b3-5667648aa4b7&#x26;width=768&#x26;dpr=3&#x26;quality=100&#x26;sign=9aae2297&#x26;sv=2" alt=""><figcaption></figcaption></figure>
{% endtab %}

{% tab title="JavaScript SDK" %}
**Check SDK**

Before writing any logic, ensure the Natively SDK is correctly installed and up-to-date in your codebase.

1. Open your project's main HTML file (or header settings) and look for the Natively script tag inside the `<head>` section.
2. Install/Update: If missing or outdated, add the following code. You can specify the SDK version in the URL (e.g., `@2.26.0`).

```javascript
<head>
  <script async onload="nativelyOnLoad()" src="https://cdn.jsdelivr.net/npm/natively@2.26.0/natively-frontend.min.js"></script>
</head>
```

{% hint style="info" %}
To ensure you are using the most up-to-date version, check the [Natively GitHub releases page](https://github.com/buildnatively/js-sdk/releases) for the latest version number.
{% endhint %}
{% endtab %}

{% tab title="AI Agents" %}
**Initialize the SDK**

AI-powered editors like Lovable, Base44, and Replit use the JavaScript SDK to implement Natively features. Before implementing any feature, the Natively SDK must be initialized in your project.

Copy the line below and paste it into your AI agent to check and set up the Natively SDK in your project.

```
Check if the following Natively SDK script is present in the <head> of index.html. If missing or outdated, add it: <script async onload="nativelyOnLoad()" src="https://cdn.jsdelivr.net/npm/natively@2.26.0/natively-frontend.min.js"></script><script>function nativelyOnLoad() { window.natively.setDebug(true); console.log("✅ Natively SDK loaded successfully."); }</script> For reference: https://docs.buildnatively.com/guides/integration/how-to-get-started https://github.com/buildnatively/js-sdk/releases
```

{% endtab %}
{% endtabs %}

### Setup Logic

{% tabs %}
{% tab title="Bubble.io Plugin" %}

### \[Element] Natively - NFC

#### **Fields:**

* **Read Alert Message** - message shown to the user when the NFC scanner is waiting for a tag to be placed near the device.
* **Write Alert Message** - message shown to the user when the NFC scanner is waiting for a tag to be placed near the device for writing.
* **Read Detected Message** - message shown when a tag is successfully detected and read.
* **Write Detected Message** - message shown when a tag is successfully detected and data has been written.
* **nfcresponse** - a predefined Bubble type `Natively - NFCResponse` that needs to be selected when working with NFC tag data.

#### **Events:**

* **NFC Read Failed** - fires when a read attempt fails.
* **NFC Write Failed** - fires when a write attempt fails.
* **NFC Write Success** - fires when data is successfully written to a tag.
* **NFC Read Success** - fires when a tag is successfully read.
* **NFC Ready To Use** - fires when the **NFC Is Available** state is received (useful for Android to confirm NFC is enabled on the device).

#### **States:**

* **Error** - error message if a read or write attempt failed.
* **Result** - the NFC tag result data.
* **NFC Tag ID** - the ID of the detected NFC tag.
* **NFC Tag Type** - the type of the detected NFC tag.
* **NFC Is Available** - Yes/No. Whether NFC is available on the device.

#### **Actions:**

* Read Data - starts an NFC read scanning session.
* Write Data - starts an NFC write scanning session:
  * **Record Data** - the data to write to the tag (text or URL). To open your app when the tag is scanned, use your Bundle ID scheme — for example: `com.bundle.id://open?url={url}` .
  * **Record ID** - a string identifier stored alongside the record on the tag. Only one record can currently be stored per tag, so this doesn't yet enable reading or writing multiple records.
  * **Record Data Type** - `text` or `uri`. When set to `uri`, scanning the written tag will automatically open the link in the device's default browser.
    {% endtab %}

{% tab title="JavaScript SDK" %}

```javascript
// ============================================================================
// NATIVELY NFC - DOCUMENTATION & EXAMPLES
// ============================================================================

const readAlertMessage = "Hold your device near an NFC tag";
const writeAlertMessage = "Hold your device near an NFC tag to write";
const readDetectedMessage = "Tag detected!";
const writeDetectedMessage = "Tag written successfully!";

const nfcService = new NativelyNFCService(
  readAlertMessage,
  writeAlertMessage,
  readDetectedMessage,
  writeDetectedMessage
);

// ============================================================================
// ALL AVAILABLE METHODS
// ============================================================================
// nfcService.available(callback)
//   - Checks whether NFC is available on the device.
//
// nfcService.read(callback)
//   - Starts a single NFC read session. Performs one read, then the session
//     ends — call read() again to scan another tag.
//
// nfcService.write(recordId, recordData, recordDataType, callback)
//   - Starts an NFC write session.
//   - recordId: string — identifier stored alongside the record. Only one
//     record can currently be stored per tag.
//   - recordData: string — the data to write (text or URL). To open your
//     app when the tag is scanned, use your Bundle ID scheme:
//     com.bundle.id://open?url={url}
//   - recordDataType: string — "text" or "uri". When "uri", scanning the
//     written tag automatically opens the link in the browser.

// ============================================================================
// CALLBACK RESPONSE FIELDS - available
// ============================================================================
// resp.status: boolean — true if NFC is available, false if not

// ============================================================================
// CALLBACK RESPONSE FIELDS - read
// ============================================================================
// resp.status: "SUCCESS" | "FAILED"
// resp.message: string — present if status is "FAILED"
// Note: the Detected Message may currently fire before a read has actually
// succeeded — always check resp.status rather than relying on it alone.

// ============================================================================
// CALLBACK RESPONSE FIELDS - write
// ============================================================================
// resp.type_format: string — e.g. "nfcWellKnown"
// resp.type: string
// resp.id: string
// resp.length: number
// resp.payload_content: string — the data written to the tag
// resp.payload_raw: string
// resp.status: "SUCCESS" | "FAILED"
// resp.message: string — present if status is "FAILED"

// --- NFC. Check Availability Example. Start ---

const available_callback = function (resp) {
  if (resp.status) {
    console.log("NFC is available");
  } else {
    console.log("NFC is not available on this device");
  }
};

nfcService.available(available_callback);

// --- NFC. Check Availability Example. End ---


// --- NFC. Read Example. Start ---

const read_callback = function (resp) {
  if (resp.status === "SUCCESS") {
    console.log("NFC tag read successfully:", resp);
  } else {
    console.log("Read failed:", resp.message);
  }
};

nfcService.read(read_callback);
// Call nfcService.read(read_callback) again to scan another tag

// --- NFC. Read Example. End ---


// --- NFC. Write Example. Start ---

const recordId = "1"; // stored alongside the record — only one record per tag currently
const recordData = "https://yourapp.com";
const recordDataType = "uri"; // "text" or "uri"

const write_callback = function (resp) {
  if (resp.status === "SUCCESS") {
    console.log("Written data:", resp.payload_content);
  } else {
    console.log("Write failed:", resp.message);
  }
};

nfcService.write(recordId, recordData, recordDataType, write_callback);

// --- NFC. Write Example. End ---
```

{% endtab %}

{% tab title="AI Agents" %}
AI-powered editors like Lovable, Base44, and Replit use the JavaScript SDK to implement Natively features.&#x20;

Copy the line below and paste it into your AI agent.&#x20;

<pre><code>[<a data-footnote-ref href="#user-content-fn-1">Your feature description</a>] using the Natively NFC SDK: const nfcService = new NativelyNFCService(readAlertMessage, writeAlertMessage, readDetectedMessage, writeDetectedMessage); readAlertMessage/writeAlertMessage are shown while waiting for a tag, readDetectedMessage/writeDetectedMessage are shown when a tag is detected (note: the detected message may currently fire before the read/write has actually succeeded — always check resp.status). nfcService.available(callback) checks if NFC is available, returning resp.status (boolean). nfcService.read(callback) starts a single NFC read session — it performs one read and ends, call it again to scan another tag — returning resp.status ("SUCCESS" or "FAILED") and resp.message on failure. nfcService.write(recordId, recordData, recordDataType, callback) starts an NFC write session — recordId: string, stored alongside the record, but only one record can currently be stored per tag; recordData: string, text or URL; recordDataType: "text" or "uri" (uri opens the link in the browser when the tag is scanned) — returning resp.payload_content (the written data), resp.status ("SUCCESS" or "FAILED"), and resp.message on failure. For reference: https://docs.buildnatively.com/natively-platform/features/nfc
</code></pre>

{% hint style="warning" %}
Replace the placeholder at the beginning with a description of what you want to build - for example: "When the user taps the scan button, read an NFC tag and display the tag content on the screen".
{% endhint %}
{% endtab %}
{% endtabs %}

### How to use

#### Always check availability first

Call `nfcService.available()` before showing any NFC-related UI to confirm the device supports NFC. On Android, the user may also need to enable NFC in their device settings - handle this gracefully by showing a message directing them to do so if NFC is unavailable.

#### Use descriptive alert messages

The alert messages shown during scanning sessions are the only feedback the user gets while waiting for a tag. Make them clear and actionable - for example: "Hold your phone near the card to scan" rather than a generic message.

#### Read vs Write

Use `read` to retrieve data from an existing NFC tag - for example, to authenticate a product, check in a user, or retrieve a URL. Use `write` to program a new or blank tag with data your app provides.

#### Only one record can be stored per tag

`recordId` is stored alongside the data you write, but tags currently support a single record - you can't write multiple records to the same tag and read them back individually.

#### Use `uri` type to open links automatically

When writing a tag with `recordDataType: "uri"`, scanning that tag on any NFC-enabled device will automatically open the URL in the device's default browser - even outside your app. This is useful for product cards, event badges, or any physical object that should direct users to a web page.

#### Use your Bundle ID scheme to open your app from a tag

To make a scanned tag open your app directly, write your app's Bundle ID scheme as the Record Data - for example `com.example.app://open?url=https://yourapp.com`. This works in combination with Universal Links and the `uri` data type.

#### Supported NFC tags

The app supports NDEF-formatted tags following the NFC Forum Type 2 (NTAG213, NTAG215, NTAG216, MIFARE Ultralight) and Type 5 (ISO15693) standards. Proprietary or non-NDEF cards - payment cards, access cards, MIFARE Classic, DESFire - are not supported.

## Troubleshooting

<details>

<summary>NFC is not working on the device</summary>

On Android, the user may need to enable NFC in their device settings before it can be used. The exact location varies by manufacturer - typically found under **Settings** > **Connected devices** > **NFC**. Use `nfcService.available()` to check if NFC is enabled before attempting to read or write.

</details>

<details>

<summary>NFC is not available on the iOS simulator or Android emulator</summary>

NFC requires a physical device with NFC hardware. It will not work on simulators or emulators. Test on a real device only.

</details>

<details>

<summary>Tag not detected during read or write</summary>

Make sure you are using a supported tag type - only **NTAG213, NTAG215, and NTAG216 (MiFare Ultralight)** have been tested and confirmed to work. Hold the device steady and close to the tag during scanning.

</details>

<details>

<summary>Write succeeds, but scanning the tag doesn't open the URL</summary>

Make sure `recordDataType` is set to `uri` and that the URL is valid and complete (including `https://`). If `recordDataType` is set to `text`, the tag content will be read as plain text and won't trigger a browser open.

</details>

<details>

<summary>App not opening when tag is scanned</summary>

Verify that the Bundle ID scheme is correctly formatted in the Record Data - for example `com.example.app://open?url=https://yourapp.com`. On iOS, Universal Links may need to be configured for the deep link to work correctly.

</details>

[^1]: Replace this placeholder
