> ## Documentation Index
> Fetch the complete documentation index at: https://react-native-nfc-kit.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Reading and writing NDEF

> The default setup: the entitlement, the usage description and the manifest a tag read needs.

This is the default setup: nothing to configure beyond installing the plugin.

```ts theme={null}
const message = await nfc.withTag({ tech: ['ndef'], timeoutMs: 20_000 }, async (tag) => {
  if (!tag.is('ndef')) throw new Error('Not an NDEF tag');
  return tag.readNdef();
});
```

## Expo

```json app.json theme={null}
{
  "expo": {
    "plugins": [
      [
        "react-native-nfc-kit",
        { "readerUsageDescription": "Hold your card near the top of the phone" }
      ]
    ]
  }
}
```

<Warning>
  `readerUsageDescription` is the text iOS shows in the scanning sheet. A default is supplied,
  because iOS refuses to create a session when the key is missing or blank and the resulting error
  says nothing about Info.plist — but the default is generic, and this string is the only
  explanation your user gets for why the phone is asking about a card. **Write your own.**
</Warning>

## Bare React Native

### `ios/<App>/<App>.entitlements`

```xml theme={null}
<key>com.apple.developer.nfc.readersession.formats</key>
<array>
  <string>TAG</string>
</array>
```

`TAG` rather than `NDEF` is deliberate. This library uses `NFCTagReaderSession`
for every technology, NDEF included, so that one code path covers them all — and
that session type requires the `TAG` format. A narrower entitlement would read
better in a review and fail at runtime.

<Note>
  The entitlement also has to exist on the provisioning profile: in the Apple Developer portal,
  enable **Near Field Communication Tag Reading** for the App ID, then regenerate the profile.
  Xcode's "Automatically manage signing" does this for you; a manually managed profile does not.
</Note>

### `ios/<App>/Info.plist`

```xml theme={null}
<key>NFCReaderUsageDescription</key>
<string>Hold your device near an NFC tag to read it.</string>
```

### `android/app/src/main/AndroidManifest.xml`

```xml theme={null}
<uses-permission android:name="android.permission.NFC" />
<uses-feature android:name="android.hardware.nfc" android:required="false" />
<activity android:name=".MainActivity" android:launchMode="singleTop">
  <!-- your existing intent filters stay here -->
</activity>
```

`android:required="false"` keeps the app installable on devices without an NFC
controller. Set `requireNfcHardware: true` only if the app is useless without it —
`true` removes those devices from your Play Store audience entirely.

<Warning>
  `singleTop` is not optional. Without it Android recreates the activity every time a tag arrives
  through an intent, losing whatever was in flight. It is applied unconditionally because it is
  harmless when no intents are configured.
</Warning>

## Writing

Writing needs no extra configuration, but it does need the tag to allow it:

```ts theme={null}
import { createUriRecord, encodedMessageLength } from 'react-native-nfc-kit/ndef';

const records = [createUriRecord('https://www.ventry.es/entrada')];

await nfc.withTag({ tech: ['ndef'] }, async (tag) => {
  if (!tag.is('ndef')) throw new Error('Not an NDEF tag');

  const status = await tag.getNdefStatus();
  if (!status.writable) throw new Error('This tag is locked');
  if (status.capacity < encodedMessageLength(records)) {
    throw new Error('Message too large for this tag');
  }

  await tag.writeNdef(records);
});
```

`writeNdef` takes records; `writeNdefBytes` takes an already-encoded message, for
when you have bytes from elsewhere. `readNdef` and `readNdefBytes` are the same pair
in the other direction.

<Tip>
  A blank factory tag is often **NDEF formatable** rather than NDEF, which is a different
  technology: ask for `tech: ['ndef', 'ndefFormatable']` and narrow with `tag.is('ndefFormatable')`
  to format it on first write.
</Tip>

## Next

<Columns cols={2}>
  <Card title="The NDEF codec" icon="code" href="/ndef">
    Every record type, chunking, and tag-level framing.
  </Card>

  <Card title="Background tags" icon="mobile" href="/setup/background-reading">
    Handling a tag tapped while your app is closed.
  </Card>
</Columns>
