The problem
The client is a mid-size apparel and home goods retailer with an existing iOS and Android app, originally built by GreyScript Technologies (GreyScript AI's parent company) several release cycles earlier. Their product team wanted a conversational shopping assistant that could answer "do you have this in a smaller size?" or "what would go with this jacket?" in natural language, instead of forcing users through faceted search filters most shoppers didn't use.
The hard constraint wasn't the AI feature itself; it was everything around it. This was a live app with an established release cadence, an existing checkout flow generating real revenue, and a mobile engineering team that couldn't take on a parallel rewrite. Any new feature had to ship inside the existing codebase, on the existing release train, without freezing other in-flight work or risking checkout stability.
Why "just add a chat screen" wasn't the actual plan
The initial ask from the client's product team was closer to "add a chatbot screen." In discovery, we pushed back on scoping it as an isolated screen. A shopping assistant that can't see the catalog in real time or take the user straight into checkout is a novelty, not something that changes purchase behavior. Two things mattered for it to be useful: answers aware of live inventory (not stale product data), and a direct handoff into the existing add-to-cart flow instead of describing a product and making the user go find it.
That reframed the scope from "add a chat UI" to "integrate a conversational layer into the existing product and cart APIs." It's a different and larger piece of work, but it's the one that moves the metrics the client cared about.
Architecture
Native integration, not a webview
The client's app (and our background) is native mobile, so the assistant was built as a native SwiftUI and Jetpack Compose surface rather than an embedded webview, the faster path some vendors would have proposed. That kept the interaction consistent with the rest of the app (same animation timing, design system, and accessibility support) instead of feeling like a bolted-on web widget, and avoided the performance and reliability issues webviews tend to introduce inside native apps.
Retrieval against live catalog and inventory
Product questions are answered by querying the client's existing catalog and inventory APIs in real time, not a static or periodically synced copy. This was deliberate: an assistant that tells someone an item is in stock in their size when it sold out an hour ago actively damages trust in the feature. The retrieval layer queries the same inventory service the existing product detail pages use, so answers are exactly as fresh as the rest of the app.
Conversation and product-to-cart handoff
The conversational layer handles natural-language product search, recommendation requests, and sizing and styling questions grounded in actual product metadata (not generated descriptions, because fabricated product details are a returns and trust liability for a retailer). Critically, every product it surfaces links straight into the existing product detail and add-to-cart flow used everywhere else in the app, rather than a parallel purchase path. The checkout experience, and the analytics tracking it, stayed completely unchanged.
Feature-flagged rollout
The feature shipped behind the feature-flag system the app already used, rolling out to 10% of users, then 50%, then 100% over two weeks, with the ability to switch it off instantly if anything looked wrong. That's what let it ship on the existing release cadence with zero downtime: it went out in a regular app store release, dormant for most users until the flag opened it up, with no dedicated release event.
Challenges and tradeoffs
- Keeping native performance parity with the rest of the app took real profiling work. The client holds its app to a strict internal bar for cold start and interaction latency. Early versions of the assistant's product-lookup calls added noticeable jank on older Android devices. We moved the retrieval call to fire as soon as intent was classified, rather than waiting for the full message to be processed, which cut meaningful latency from the perceived response time.
- Fabricated styling suggestions were a real early failure mode. In testing, the model occasionally suggested pairing items that weren't actually in stock together, or invented a styling rationale not grounded in the product data. We constrained styling responses to reference only products returned by an actual catalog query rather than letting the model free-generate suggestions. That largely fixed the problem, at the cost of some conversational flexibility, a tradeoff we made deliberately for reliability.
- The feature-flagged rollout surfaced a real inventory-sync edge case. During the 50% stage, we found a rare race condition: an item could show as available in the assistant's response but sell out by the time the user tapped through, because of a caching layer on the inventory API we hadn't accounted for. We shortened the cache TTL for assistant-driven lookups to close the gap, accepting slightly higher API load in exchange for accuracy.
Results
The feature shipped in six weeks from scoping to full rollout, inside the client's existing release cadence, with zero minutes of app downtime or checkout disruption during rollout. Users who engaged with the assistant showed a 22% higher add-to-cart rate than users of standard search and filtering in the same period. That comparison reflects engaged users specifically and isn't a claim about the feature's effect on the full user base.
Because it was built as a native integration into the existing product and cart flow rather than a parallel system, the client's analytics and checkout instrumentation needed no changes to keep tracking the funnel correctly, which meaningfully reduced engineering risk and the QA surface for the release.
What we'd do differently
We'd load-test the inventory API's caching behavior under the assistant's query pattern before the 50% rollout stage rather than during it. The race condition wasn't a design flaw so much as an interaction between two systems (the standard product pages and the new assistant) that we hadn't tested together at scale, and catching it a stage earlier would have avoided a same-day hotfix.