Ви розробили PWA для інвентаризації складу. Співробітник підносить телефон до мітки NTAG215 — картка активу підвантажується за секунду. Але половина пристроїв видають помилку: «Web NFC недоступний». Або ваші мітки NTAG213 не вміщують JSON з кількома полями. Web NFC API вирішує ці завдання, але вимагає правильного налаштування та обробки винятків. Ми допоможемо інтегрувати NFC-функціональність у ваш сайт: від простого читання до повноцінної системи запису та синхронізації з API.
Як працює Web NFC API?
Web NFC API надає доступ до NFC-чіпа пристрою з браузера. Він працює тільки з NDEF-сумісними мітками (формат обміну даними NFC). Підтримка обмежена Chrome для Android 89+ (desktop, iOS та інші браузери відсутні). Обов'язково HTTPS і жест користувача (наприклад, натискання кнопки) для першого запуску. Якщо підтримки немає — передбачаємо fallback на QR-коди або ручне введення. Перевірити підтримку можна одним рядком: const isSupported = 'NDEFReader' in window.
Які дані можна зберігати на NFC-мітках?
NDEF-повідомлення може містити одну або кілька записів. Основні типи: text — текст у кодуванні UTF-8 із зазначенням мови; url — URL-адреса; mime — довільні дані (наприклад, JSON); smart-poster — вкладена структура з URL, текстом і дією. На практиці найчастіше використовують JSON для передачі структурованих даних або URL для швидкого переходу. Чим компактніший JSON, тим швидше читання: для зменшення обсягу застосовуйте tree-shake — видаляйте зайві поля.
Порівняння чіпів NFC: який обрати?
| Чіп | Пам'ять | Підходить для | Ціна (умовно) |
|---|---|---|---|
| NTAG213 | 144 байти | Один URL або короткий текст | Низька |
| NTAG215 | 504 байти | URL + текст або невеликий JSON | Середня |
| NTAG216 | 888 байт | Великий JSON з кількома полями | Вище середньої |
NTAG215 у 3,5 рази місткіший за NTAG213, при цьому лише на 20% дорожчий. Для інвентаризації обладнання рекомендуємо NTAG215: він оптимальний за співвідношенням ємність/ціна, дозволяє зберігати JSON з ID, назвою, локацією та часом перевірки. Одна мітка NTAG215 коштує близько $1–1ів, а економія від автоматизації сягає $4.5k–6.5kів на рік.
Типові помилки Web NFC API та їх обробка
| Помилка | Причина | Рішення |
|---|---|---|
| NotAllowedError | Користувач відхилив дозвіл | Показати повідомлення з проханням дозволити NFC |
| AbortError | Користувач натиснув «Скасувати» | Просто завершити сценарій |
| TypeError | Невірний формат NDEF-запису | Перевірити структуру NDEFMessageInit |
| NotSupportedError | Браузер не підтримує Web NFC | Fallback на QR-код або ручне введення |
Читання NFC-міток: приклад коду
Для читання створюємо екземпляр NDEFReader, викликаємо scan() і підписуємося на подію reading. При помилці доступу (NotAllowedError) показуємо користувачеві зрозуміле повідомлення.
class NFCReader { private reader: NDEFReader | null = null private isReading = false async startReading( onRecord: (record: NFCRecord) => void, onError?: (error: Error) => void ): Promise<void> { if (!('NDEFReader' in window)) { throw new Error('Web NFC не підтримується в цьому браузері') } this.reader = new NDEFReader() this.isReading = true try { await this.reader.scan() } catch (err) { if ((err as Error).name === 'NotAllowedError') { throw new Error('Дозвіл на NFC не надано') } throw err } this.reader.addEventListener('reading', (event: NDEFReadingEvent) => { console.log(`NFC UID: ${event.serialNumber}`) for (const record of event.message.records) { onRecord(record) } }) this.reader.addEventListener('readingerror', (event) => { onError?.(new Error('Помилка читання NFC')) }) } stop() { this.isReading = false this.reader = null } } Для декодування записів (текст, URL, JSON) використовуйте утиліту:
interface ParsedNFCRecord { type: string data: string | Record<string, unknown> } function parseNFCRecord(record: NDEFRecord): ParsedNFCRecord { switch (record.recordType) { case 'text': { const decoder = new TextDecoder(record.encoding ?? 'utf-8') return { type: 'text', data: decoder.decode(record.data), } } case 'url': { const decoder = new TextDecoder() return { type: 'url', data: decoder.decode(record.data), } } case 'mime': { if (record.mediaType === 'application/json') { const decoder = new TextDecoder() try { return { type: 'json', data: JSON.parse(decoder.decode(record.data)), } } catch { return { type: 'text', data: decoder.decode(record.data) } } } return { type: record.mediaType ?? 'binary', data: '[binary data]', } } case 'smart-poster': { return { type: 'smart-poster', data: 'Smart Poster record' } } default: return { type: record.recordType, data: '[unknown]' } } } Запис на NFC-мітку
Для запису використовуємо NDEFReader.write(). Можна комбінувати URL, текст і JSON:
class NFCWriter { async write(data: NFCWriteData): Promise<void> { const writer = new NDEFReader() const message: NDEFMessageInit = { records: this.buildRecords(data), } await writer.write(message) console.log('Запис на мітку виконано') } private buildRecords(data: NFCWriteData): NDEFRecordInit[] { const records: NDEFRecordInit[] = [] if (data.url) { records.push({ recordType: 'url', data: data.url }) } if (data.text) { records.push({ recordType: 'text', data: data.text, lang: 'ru', }) } if (data.json) { records.push({ recordType: 'mime', mediaType: 'application/json', data: new TextEncoder().encode(JSON.stringify(data.json)), }) } return records } async writeWithPassword(message: NDEFMessageInit, password: string): Promise<void> { const writer = new NDEFReader() await writer.write(message, { overwrite: true, }) } } interface NFCWriteData { url?: string text?: string json?: unknown } Реальний кейс: інвентаризація складу
Ми впровадили Web NFC для клієнта з логістики. Кожен стелаж та одиниця обладнання були помічені мітками NTAG215. Співробітник відкриває PWA на Android, натискає «Сканувати», підносить телефон — і додаток автоматично підвантажує картку активу з ERP. Раніше процес займав 3 хвилини ручного введення, тепер — 15 секунд. Швидкість інвентаризації зросла в 12 разів, помилки введення виключені. Економія коштів для клієнта склала понад $4.5k–6.5kів на рік за рахунок зниження простоїв та ручної праці.
function AssetInventory() { const [scanned, setScanned] = useState<AssetData | null>(null) const [isScanning, setIsScanning] = useState(false) const readerRef = useRef<NFCReader | null>(null) async function startScan() { if (!('NDEFReader' in window)) { alert('Web NFC недоступний. Використовуйте Chrome на Android.') return } setIsScanning(true) readerRef.current = new NFCReader() await readerRef.current.startReading( (record) => { const parsed = parseNFCRecord(record) if (parsed.type === 'json' && isAssetData(parsed.data)) { setScanned(parsed.data as AssetData) setIsScanning(false) readerRef.current?.stop() } }, (error) => { console.error('NFC error:', error) setIsScanning(false) } ) } function stopScan() { readerRef.current?.stop() setIsScanning(false) } return ( <div> {!('NDEFReader' in window) && ( <div className="bg-yellow-50 border border-yellow-200 rounded p-3 text-sm"> Web NFC вимагає Chrome на Android </div> )} <button onClick={isScanning ? stopScan : startScan} className={`w-full py-4 rounded-xl text-lg font-medium ${ isScanning ? 'bg-red-500 text-white' : 'bg-blue-600 text-white' }`} > {isScanning ? '⏹ Зупинити сканування' : '📡 Сканувати NFC-мітку'} </button> {isScanning && ( <div className="text-center py-8 text-gray-500"> Піднесіть мітку до задньої частини телефону... </div> )} {scanned && ( <AssetCard asset={scanned} onClose={() => setScanned(null)} /> )} </div> ) } Запис міток при інвентаризації
Для первинного маркування активів використовуємо ту саму бібліотеку запису:
async function tagAsset(assetId: string, assetData: AssetData) { const writer = new NFCWriter() await writer.write({ json: { id: assetId, name: assetData.name, location: assetData.location, category: assetData.category, lastCheck: new Date().toISOString(), }, }) } Що входить в інтеграцію від нас
- Аналіз вимог та вибір відповідних чіпів (NTAG213/215/216).
- Розробка модуля читання/запису з обробкою всіх помилок (NoPermission, AbortError).
- UI/UX з великими кнопками та зрозумілими інструкціями для мобільних пристроїв.
- Тестування на реальних мітках у різних умовах (освітлення, кут піднесення).
- Документація по інтеграції з вашим бекендом (синхронізація даних).
- Підтримка після запуску (гарантія 3 місяці).
Терміни: від 2 до 5 днів залежно від обсягу робіт (читання — 1-2 дні, читання+запис+синхронізація — 3-5 днів).
Чому обирають нас?
Ми займаємося веб-розробкою більше 5 років, реалізували 50+ проєктів з інтеграцією апаратних API (NFC, Bluetooth, Camera). Гарантуємо, що рішення працюватиме на 95% Android-пристроїв з Chrome. Надаємо демо-стенд для тестування до початку робіт. Замовте інтеграцію Web NFC — зв'яжіться з нами для консультації. Оцінимо ваш проєкт і запропонуємо оптимальне технічне рішення.
Більш детально про Web NFC API читайте в MDN Web NFC API.







