Product research

I audited 11 real apps built with AI coding tools. Almost all of them broke the same way.

Not a vibe. A list of specific, repeatable defects, pulled from apps other people actually shipped.

July 2026 · 11 apps audited · ~9 min read
A grid of cropped screenshots from the audited apps: identical fake stock deltas, a mismatched-currency account card, a raw React error overlay, and a marketing nav bolted onto an internal ops table.

I wanted to know, concretely, what "AI-built software looks off" actually means, not as a vibe but as a list of specific, repeatable defects. So I stopped speculating and pulled real examples: apps other people built with v0, published to its public community gallery, with genuine traction: hundreds of forks and likes, not cherry-picked outliers.

Eleven apps. Two verticals: internal tools and fintech. I opened every one, clicked through every screen, and wrote down exactly what broke. I expected the failures to be scattered: a bad color choice here, a missing empty state there. They weren't. The same handful of mistakes showed up over and over, across apps that had nothing to do with each other, built by different people, for different purposes. That repetition is the finding. If eleven unrelated apps make the same mistake, it isn't eleven mistakes. It's one mistake the tooling keeps making, and no amount of better prompting is going to fix it, because the model is getting the logic right every time. It's the layer above logic (what a number, a color, or a blank screen is supposed to communicate) that keeps falling through.

The method

Six internal-tools apps, pulled from v0's community gallery: VetCRM (a veterinary clinic dashboard, 300 remixes, 97 likes), two Etihad Cargo tools (an AWB tracker and an airport performance table), UXBooster (an analytics dashboard, 295 remixes), CampaignHub (a marketing dashboard), and Meridian (a financial analytics dashboard, 420 remixes, 115 likes, the most popular app in the sample).

Five fintech apps, same gallery, same standard, searched across "fintech dashboard," "banking dashboard," "expense tracker," "trading," and "invoice," kept everything with meaningful engagement: LoanTech (193 forks), an Expense Tracker (344 forks), the Primium Gold banking dashboard (203 forks), a real-time trading chart (326 forks), and an Advance Invoice Generator (487 forks, the highest-engagement app the fintech search turned up).

I tried to extend this to Bolt.new and Lovable output too, for a fairer picture. I couldn't. Bolt's public gallery is gone. The link 404s into a broken project-import view, and there's no showcase left in their nav, only a Discord invite. Lovable never had a comparable gallery to begin with. GitHub searches for Bolt or Lovable fintech projects top out at one star, nowhere near the traction that made the v0 sample worth trusting. So this is a v0 audit, honestly labeled as one, worth a revisit if either tool ships a real gallery later.

What kept breaking

Color meant nothing. VetCRM's stat-card icons are green, blue, orange, and pink for no discernible reason. A tile reading "14 Pending" renders in alarm red. LoanTech's "Biggest daily movers" list shows the identical fake "+4.5%" next to all three stocks, regardless of which way they actually moved. Expense Tracker assigns yellow, red, blue, orange, and green to spending categories with no logic connecting color to meaning. In every case, color was picked to look varied, not to say anything, which means it actively lies to anyone who's learned to trust red-means-bad, green-means-good.

LoanTech's 'Biggest daily movers' panel showing all three tickers with the identical fake +4.5% delta.
LoanTech's "Biggest daily movers": three different stocks, one delta, copy-pasted.

Numbers didn't agree with themselves. Primium Gold's own account card can't settle on a single currency format: the headline balance reads "$34,280.56" with a thousands separator, while "Remaining Limit: $1376.98" (same card, same currency, one field down) drops the comma entirely. Its Expense Tracker cousin shows "$0.00 this month" next to a running total that clearly includes March transactions, and a "Recent Expenses" list that isn't sorted by date, despite the label promising it is. These aren't edge cases; they're the first screen a user sees.

Primium Gold's account card showing $34,280.56 with a thousands separator directly above Remaining Limit: $1376.98 without one.
Same card, same currency, two different formatting rules: $34,280.56 vs $1376.98.

Nothing else existed besides the happy path. Five of the six internal-tools apps show sample data forever. There's no evidence any of them has ever rendered a loading, empty, or error state, because none of them were built to. VetCRM was the lone exception, with a genuinely good "All clear for now" empty state, proof this isn't hard, just skipped. When something does go wrong, it goes wrong loudly: both LoanTech and the Advance Invoice Generator (two apps with nothing else in common, built for different purposes, by different people) threw the exact same raw React error overlay mid-workflow. Not a similar error. The identical one.

LoanTech's live preview showing a raw React error overlay reading 'Encountered a script tag while rendering', with the app visible behind it.
LoanTech, mid-task: the raw React overlay, not a friendly error state.

Real-time data wasn't real, and said so quietly. The trading-chart app's own author description states the chart "only animates the last data point which creates a more realistic trading chart experience." That's synthetic movement, deliberately dressed up as live, disclosed only in the fine print a user would never read. Nothing on the actual screen tells you what you're looking at is fake.

The BTC/USD real-time chart template, showing a live-looking price line with a Live Updates toggle. Nothing on screen discloses that only the last data point is real.
Looks live. Nothing on screen says only the last point actually is.

Structure kept getting borrowed from the wrong place. Etihad's internal cargo-tracking tool sits under a full public marketing nav (About, Products, Services, News) bolted onto what is unmistakably an operational screen. Etihad's other tool, the airport performance table, has columns labeled "ERT," "COL," and "CRT" that are never defined anywhere, rendering a 64% failure rate in the same plain black text as a 5% one. Primium Gold's entire top navigation is icon-only, no labels, no tooltips, on buttons tied to real account actions. And right next to LoanTech's masked account balances ("****", correctly hidden) sit two visually different button styles doing the same job, a small inconsistency that undermines trust in the one part of the screen where trust matters most.

Etihad Cargo's AWB tracker: a full public marketing nav (About us, Products, E-services, Network, News, Help) sitting directly above the internal AWB operations table.
A marketing nav (About us, Products, News) bolted onto an internal ops screen.

Filter bars and dense tables had no plan for their own size. Etihad's AWB search page packs a MAWB search box, a status dropdown, an excursions dropdown, an origin picker, a destination picker, two date-range fields, and Clear/Search buttons (ten-plus controls) into the same row at every viewport, with no logic for what happens as the window narrows. It doesn't crash or overflow; it does something quieter and worse. Below desktop width the row wraps, but each field keeps the same fixed width, so labels just get cut off mid-word: "Select Destination" becomes "Select…", "Tagged at start date" becomes "Tagged," "Updated at start date" becomes "Updated." Nothing is broken, but a user can no longer tell which field is which. This is what happens when a layout is generated to look complete at one specific viewport width and never stress-tested past it.

Etihad Cargo's AWB filter row at laptop width, where the destination, tagged-date, and updated-date fields have all had their labels clipped down to fragments like 'Select…' and 'Tagged.'
Same filter row, narrower window: labels truncate to "Select…" and "Tagged", and no one can tell which field is which.

Why this keeps happening

None of these are bugs in the sense of broken logic. The totals compute, the forms submit, the charts render. What's missing is judgment: the layer that decides what a visual choice means. Current AI coding tools are extremely good at producing a screen that works and looks plausible in a screenshot. They have no consistent opinion on whether red should mean "bad" every time, whether every number on a page should round the same way, or whether a blank state deserves the same design attention as a full one. Every app in this sample got that judgment call wrong somewhere, because nothing in the generation process makes that judgment structural. It's up to whichever prompt happened to ask for it, on whichever screen someone remembered to ask.

That's a component-library problem, not a prompting problem. It's fixable exactly once, at the level of the building blocks, instead of once per screen, forever, by every person using these tools.

What we built instead

OnSystem before and after: a generic AI-generated fintech screen next to the same screen rebuilt with OnSystem's Fintech kit, showing semantic color, consistent formatting, and masked values.
Same screen, same data, before and after dropping in OnSystem's Fintech kit.

That's the whole premise behind OnSystem. Two kits, Internal Tools and Fintech: drop-in React and Tailwind components built directly against this failure list, not a general design-system wishlist. Five semantic color roles (success, warning, danger, info, neutral) that every status indicator, delta, and category tag has to pull from, so no more identical fake deltas or alarm-red for no reason. Shared currency, percent, and decimal formatters baked into the components instead of left to whoever wrote that screen. Every data-bearing component ships loading, empty, and error states as defaults, not afterthoughts, including a masked-value component with one consistent reveal pattern, and a live-vs-demo-data badge for anything claiming to be real-time. An app shell that's structurally impossible to confuse with a marketing site. A filter bar with an actual overflow strategy past four controls.

Grid overview of everything included in an OnSystem kit: components, themes, and the AI context pack.
What's inside a kit: components, five audited themes, and the AI context pack that keeps new screens on-system.

Same install either way: npx shadcn add, or just ask your AI assistant to add the component directly. The registry is MCP-ready, so Claude, Cursor, and the rest read the same config. One-time purchase, perpetual access and free updates.

If any of this looked familiar, if you've shipped a screen with a fake delta, an unlabeled icon button, or a "live" badge on data that wasn't, you're not alone, and it's not a you problem. It's what the tools currently do by default.

Ship screens that look intentional

One-time purchase, instant delivery, perpetual access and free updates.


Methodology note: all eleven apps were pulled from v0's public community gallery based on fork/like counts alone, not selected to make a point. Screenshots and specifics available on request. Happy to show the receipts on any of these.