From Vibe-Coded POS to Real Device: The Production Checklist
A vibe-coded POS looks ready in a laptop browser, then fails on an iPad when you try to print a receipt or tap a card. Here is the complete engineering checklist to take an AI-generated checkout to real counter hardware—and how to skip the 90% of native plumbing using Final's MCP server.

Prompting Claude Code, Cursor, or Lovable to build a restaurant or retail register takes about twenty minutes. By minute twenty-five, you have a slick React grid, modifier modals that snap open, a working cart sidebar, and a "Pay Now" button that fires confetti across your MacBook screen. Then you open that same URL in Safari on an iPad at a real counter, try to pair a Bluetooth receipt printer, and hit a wall.
Taking a vibe coded POS to production means crossing the gap between a browser sandbox and locked-down operating system APIs. A web app running in Mobile Safari cannot talk to Bluetooth Classic thermal printers, trigger an RJ12 cash drawer kick, read an EMV chip card, or initiate Tap to Pay on iPhone. The UI is the easy 10% that an AI assistant writes in an afternoon. The remaining 90% is integer accounting, hardware transport protocols, payment SDK entitlements, and Apple App Review compliance.
To make a vibe coded POS work on a physical counter, you either wire up the native hardware, payment, and offline layers yourself, or you point your AI coding tool at a commerce infrastructure layer that already holds those certifications. This vibe coding production checklist walks through every engineering requirement to ship your own build from scratch.
Why Does the Browser Preview Lie About Counter Hardware?
Desktop Chrome and Mobile Safari operate under completely different hardware security models. When you test a generated checkout in Cursor or Bolt on your laptop, the app lives in a permissive local environment with stable fiber internet, mock payment callbacks, and standard window.print() dialogs that pop up a PDF preview.
Put that web app onto a store iPad and three things break immediately:
No Web Bluetooth or WebUSB on iOS: Apple blocks Web Bluetooth and WebUSB in WebKit. Even if you install Chrome or Edge on an iPad, iOS forces those browsers to use WebKit under the hood. Your web app has zero access to nearby Bluetooth receipt printers or USB barcode scanners.
System print dialogs kill counter speed: Calling
window.print()on an iPad opens the iOS AirPrint modal. A cashier has to tap to select a printer, tap to confirm copies, and wait four seconds for iOS to rasterize a full-page PDF onto an 80mm thermal roll.Web card forms are not card-present transactions: Typing a customer's card into a Stripe Elements web form or triggering a QR code checkout routes the sale as an online transaction. In the US, online transactions on Final Pay cost 2.79% + $0.30 instead of in-person card rates of 2.49% + $0.10. Worse, keying or scanning a web form leaves the merchant liable for every card-not-present chargeback.
Step 1: Move Money Math to Integer Cents and Server-Side Totals
TL;DR: Never let your AI calculate currency using JavaScript floating-point decimals on the client. Convert all prices to integer minor units (cents) and re-verify tax, discounts, and split tenders on the server before calling your payment processor.

Standard cash drawers don't connect to the tablet at all—they plug into the receipt printer via an RJ12 cable and open when the printer receives a 5-byte hex pulse.
AI coding models love writing const total = price * quantity * (1 + taxRate) in TypeScript. In IEEE 754 floating-point math, 19.99 * 3 evaluates to 59.970000000000006, and adding an 8.25% tax rate creates rounding drift that causes payment SDKs to reject the charge payload.
Before you touch a card reader, refactor every price, discount, tax line, and tip into integer minor units (1999 for $19.99 USD). When agency founders like Alex build custom checkouts for local cafés and boutiques, floating-point drift on split bills is one of the fastest ways to break live testing.
Your money calculation engine has to handle four edge cases deterministically:
Penny allocation on split checks and percentage discounts: If three diners split a $10.00 appetizer three ways (
1000 / 3), two guests must pay333cents and one guest must pay334cents. Round all three to333, and your order ledger stays open with a 1-cent balance that prevents the table from closing.Inclusive vs. exclusive tax rules: In the US and Canada, sales tax is added on top of the subtotal. In the UK, Europe, and Australia, VAT and GST are included in the shelf price. Your tax engine must support both models and calculate compound taxes (or tax-exempt modifiers like whole beans vs. prepared espresso) per line item rather than as a flat percentage on the cart total.
Discount application order: If a cashier applies a $5.00 coupon to a $20.00 item, is sales tax calculated on $20.00 or $15.00? Manufacturer rebates and store promos follow different state and provincial tax rules, so your data schema needs a
taxable_after_discountflag.Server-side state validation: Never trust the cart total sent from the tablet UI when creating a PaymentIntent. Your backend (or local SQLite transaction engine) must recalculate the line items, modifiers, and tax rates from the product catalog before passing the exact integer amount to the payment terminal.
For a broader look at how architecture choices affect your build timeline, see our guide on How to Build Your Own POS System with AI in 2026.
Step 2: Wire Up Receipt Printers and Cash Drawers
TL;DR: Counter receipt printers require raw ESC/POS or StarPRNT byte streams sent over TCP port 9100 (Ethernet/Wi-Fi), Bluetooth Low Energy, or Bluetooth Classic. If you choose Bluetooth Classic or Lightning on iOS, you must obtain Apple MFi PPID approval from the printer manufacturer before Apple will allow your app into the App Store.

In-person EMV and contactless transactions require PCI-certified hardware or Tap to Pay entitlements rather than browser-based web card forms.
A point of sale sends raw byte arrays (ESC/POS for Epson and Sunmi, or StarPRNT for Star Micronics) directly to the printer's buffer instead of printing HTML pages. Even the cash drawer depends on the printer. Standard cash drawers like the Sunmi Max Cashiers drawer (which uses an RJ12 connection, a 3-position lock, and a 1M-cycle life) don't connect to the iPad at all. They plug into the back of the receipt printer via an RJ12 cable, and the printer fires a 24V electrical pulse to pop the drawer open when it receives a specific 5-byte hex sequence (1B 70 00 19 FA).
Wiring up printing for a vibe-coded POS comes down to three hardware transports:
1. Local Network (Ethernet or Wi-Fi via TCP Port 9100)
Network printing is the most reliable choice for a multi-printer setup, such as routing bar drinks to a bar printer and hot food to a kitchen printer. Your native wrapper opens a raw TCP socket to the printer's static IP address on port 9100 and writes the ESC/POS byte buffer. It requires zero MFi licensing from Apple, though your iOS app will need the NSLocalNetworkUsageDescription permission in Info.plist so the cashier can allow local LAN discovery.
2. Bluetooth Low Energy (BLE)
Newer portable printers support BLE using standard GATT characteristics. Because CoreBluetooth supports BLE natively without Apple's External Accessory framework, you can connect and send byte chunks in 180-byte to 512-byte MTU packets without MFi paperwork. The tradeoff is speed: printing a long receipt with a bitmap logo over BLE feels noticeably slower than Ethernet.
3. Bluetooth Classic or Lightning/USB (Requires Apple MFi)
Most existing Bluetooth thermal printers sitting in restaurants today use Bluetooth Classic (SPP/IAP2). On Android, you can open a standard RFCOMM socket in an afternoon. On iOS, Bluetooth Classic accessories are locked behind Apple's MFi (Made for iPhone/iPad) program.
To ship an iOS app that talks to an MFi printer, you must:
Integrate the manufacturer's native iOS SDK (such as the StarIO10 or Epson ePOS2 SDK).
Declare the printer's exact protocol string (for example,
jp.star-m.starpro) underUISupportedExternalAccessoryProtocolsin yourInfo.plist.Submit an MFi application to the printer manufacturer (Star or Epson) with your App Store Bundle ID and company details.
Wait for the manufacturer to approve your app with Apple and issue a PPID (Product Plan ID).
Paste that PPID into the "App Review Information" notes in App Store Connect. Without a valid PPID on file, Apple's reviewers will reject your binary under Guideline 2.5.4.
Step 3: Choose How You Will Take Cards in Person
You cannot vibe-code an EMV kernel. Reading a contact chip or contactless NFC tap requires PCI PTS-certified hardware and an encrypted point-to-point SDK from a payment processor like Adyen or Stripe.
First, decide how your app will communicate with the card reader:
Server-driven smart terminals: Devices like the S700 or Verifone V400m connect to Wi-Fi or Ethernet and expose a cloud REST API. Your backend sends a charge request to the processor's API, and the processor wakes up the terminal on the counter. This is the easiest path for a browser-based or vibe-coded POS because your frontend doesn't need a native Bluetooth bridge.
Bluetooth mobile readers: Pocket readers (like the Stripe Reader M2 or BBPOS WisePad 3) pair directly to your phone or tablet via Bluetooth. Your app must run inside a native iOS or Android container that embeds the processor's Terminal SDK.
Tap to Pay on iPhone and Android: Accepting contactless cards directly on the merchant's phone without an external dongle is huge for line-busting and pop-up retail. On Android, this requires a device with a functioning NFC antenna, Google Play Integrity passes, and the processor's Tap to Pay SDK. iOS adds a legal and technical hurdle: you must have an Organization Apple Developer account (Individual accounts are rejected), request the Tap to Pay on iPhone Entitlement (
com.apple.developer.proximity-reader.payment.acceptance) from Apple, pass Apple's UX design checklist for payment prompts, and configure an NFC background tag reader session.
Regardless of which hardware path you choose, your state machine has to handle partial authorizations (when a prepaid gift card only covers $15.00 of a $40.00 tab), idempotent payment keys, and network timeouts where you query the terminal's last transaction status before retrying to prevent double charges.
Step 4: Wrap or Rebuild as a Native App and Pass App Review
Once you add native Bluetooth printing or an embedded Terminal SDK, your web app can no longer run inside a standard browser tab. You have to wrap your React or Vue codebase using Capacitor, or port the UI components into React Native or Flutter.
Prompting Claude Code to scaffold a Capacitor bridge for ESC/POS printing works well, but getting the compiled .ipa binary through Apple App Store Review is where weekend projects stall out for weeks. Prepare for four specific App Review blockers:
Hardware demo videos: Apple reviewers do not have a Star TSP100 receipt printer or a BBPOS card reader sitting on their desk in Cupertino. If your app requires hardware pairing to reach the checkout screen, Apple will reject it for being untestable. You must build a demo/sandbox mode into the production binary AND record an unedited video showing your app running on a physical iPad, taking a payment, and printing a ticket.
Location permissions for Bluetooth card readers: Both iOS and Android require runtime Location permissions (
NSLocationWhenInUseUsageDescription) during Bluetooth card reader connection so the payment processor can verify the merchant isn't processing cards outside their underwritten country. Vague permission prompts get flagged.In-App Purchase (IAP) confusion: Because your app has a "Checkout" screen and charges credit cards, novice reviewers occasionally mistake a point-of-sale app for digital goods and demand you use Apple In-App Purchase (which takes 30%). State clearly in your review notes that the app is a physical merchant POS governed by Guideline 3.1.5(a) for real-world goods and services.
Kiosk mode and Guided Access: On the store counter, you also need to handle device lifecycle: preventing the screen from auto-locking during a rush (
UIApplication.shared.isIdleTimerDisabled = true) and recovering cleanly when iOS kills backgrounded WebViews under memory pressure.
Step 5: Keep Ringing Sales When Store Wi-Fi Drops Mid-Shift
A restaurant owner running a 60-seat dining room on a Friday night cannot tell a line of twenty customers to wait because the ISP router rebooted. A production POS must be local-first.

Deploying an AI-built checkout flow onto certified commerce infrastructure lets custom workflows run natively on counter stations with hardware and offline support built in.
When you vibe-code an app, the AI typically writes direct fetch() or Supabase calls on every button tap. If the internet drops for thirty seconds, the product grid goes blank and the register freezes.
Surviving real store conditions takes three offline mechanisms:
Local catalog and tax caching: Sync the entire product catalog, modifier trees, tax rules, and staff PIN hashes into an on-device SQLite database or IndexedDB on startup. Every cart interaction must read from local storage in under 10 milliseconds.
An append-only outbox queue: When a cashier rings up a cash sale or an offline-forwarded card transaction while disconnected, write the completed order event to a local persistent queue with a client-generated UUID. When connectivity returns, a background worker drains the queue to the cloud without duplicating orders.
Cash drawer reconciliation (Z-reports): At the end of the night, the manager counts the physical bills in the drawer. Your app must track starting float, cash sales, cash refunds, paid-in/paid-out petty cash events, and expected drawer balance per shift, even if half those sales happened while the store was offline.
Or Skip Steps 2 Through 5: Run Your Vibe-Coded Checkout on Final's Rails
None of the five steps above have anything to do with the bespoke workflow you actually wanted to build, whether that's a dry-cleaning drop-off intake form, a custom seat-map bill splitter for a bistro, or a multi-step serial-number trade-in screen for a vintage electronics shop.
That custom checkout screen is the 10% where AI coding tools shine. The other 90% (MFi PPIDs, Adyen/Stripe terminal certifications, ESC/POS byte routing, offline SQLite queues, and App Store review videos) is undifferentiated plumbing.
We built Final POS so makers, agencies, and merchants can vibe-code the custom checkout experience and deploy it directly onto certified commerce rails without touching native SDKs or App Store Connect.
Connect Claude Code or Cursor Directly via MCP
You can describe your workflow directly in Final Build in your browser (every account includes 1,000 free build credits per day, up to 5,000 a month, with no monthly software fee), or you can build a flow with your own AI tool over MCP using Claude Code or Cursor connected to our Model Context Protocol (MCP) server at finalpos.com/mcp.
Driving Final over MCP means your AI assistant calls structured commerce tools directly rather than generating a disconnected React mockup that stops at the browser edge:
get_scaffoldto pull the commerce schema, catalog bindings, and hardware hooks.validate_flowto check that tax rules, payment actions, and state transitions are valid before running.start_previewandsync_previewto watch your checkout update live as you prompt.deploy_flowandopen_in_builderto push the finished flow straight to your physical Stations.
What Final Handles Underneath Your Flow
Once you deploy a flow (see our step-by-step guide on how to build and deploy your first flow), it runs natively inside Final Station on iOS, Android, macOS, Windows, or our all-in-one S700 POS terminal. When you set up a Native Station, it appears in the Merchant Hub under Run → Stations on the Native tab, where you can rename it, view device info, and pair a card reader. Because Final Station is already a certified native app in the App Store and Google Play, you inherit the entire hardware and payment stack on day one:
Real hardware wired automatically: Multi-printer routing on a Station (so each print block lands on its printer at the same moment), barcode scanners, customer-facing displays, and cash drawers work out of the box without MFi applications or raw hex debugging. When you test your flow, Signals show every command your flow sends to the point of sale live, and the Issue inbox collects problems from your deployed flow in the field.
Built-in card-present payments: Final Pay (our Adyen-powered payment processing operating in 24+ countries) gives your flow instant access to Tap to Pay on iPhone and Android, plus Bluetooth and countertop POS terminals. There are no monthly fees, no terminal activation fees, and no lock-in contracts. Cash is always $0, and in-person card rates are 2.49% + $0.10 in the US and worldwide, 1.99% + $0.10 CAD in Canada (0.5% + $0.07 for Interac debit), and 0.99% + €0.10 in Europe, with next-day payouts included.
Offline resilience and back-office management: As covered in getting started with Build, your flows run on your Final POS Stations and work with your real data (catalog, multi-location inventory, tax rules, and staff permissions in Manage) while keeping sales running offline when the store Wi-Fi drops.
Your Next Move
Building a standalone commercial POS product from scratch and owning the entire native stack starts with three moves: rip floating-point math out of your cart, apply for your printer manufacturer's MFi PPID before writing your iOS bridge, and apply for Apple's Tap to Pay entitlement under an Organization account today so paperwork doesn't block your launch.
If you want your custom checkout running on an iPad or POS terminal at the counter this afternoon with receipt printers firing and Tap to Pay live, create a free account at Final POS, connect your AI assistant to finalpos.com/mcp (or prompt inside Build), and ship your flow straight to Final Station. Finally.
Frequently asked questions
Why does my vibe-coded POS not work on hardware?
Browsers on iPad and iPhone run on WebKit, which blocks Web Bluetooth and WebUSB, so a web app cannot talk directly to Bluetooth receipt printers or wired USB accessories. Standard web pages also cannot accept in-person EMV chip or NFC tapped cards. Both require a native app wrapper integrated with certified hardware and payment SDKs.
Do I need MFi approval to print from my app?
You only need Apple MFi (Made for iPhone/iPad) approval if your iOS app connects to printers over Bluetooth Classic or a Lightning/USB cable. You get this through the printer manufacturer (such as Star Micronics or Epson), who issues a PPID (Product Plan ID) to paste into your App Store Review notes. Network (Ethernet/Wi-Fi) and Bluetooth Low Energy (BLE) printers do not require MFi approval.
Can a vibe-coded POS take card payments?
Yes, but you only get in-person card rates if you integrate a payment processor's native Terminal SDK (to drive a certified card reader) or obtain Apple's Tap to Pay on iPhone entitlement under an Organization developer account. Entering card details into a web checkout form routes the sale as a higher-cost, higher-risk card-not-present online transaction.
