The Web-to-App Discount Flow: How to Turn One Ad Click Into an Install and a Purchase

Website-first ad traffic, an in-app-only discount, and a purchase that still gets attributed back to the original ad. Here is the exact mechanism, what campaign type to use, and why most teams get the click-ID continuity wrong.

The Web-to-App Discount Flow with cart, discount tag, browser, link, and app store icons with ChottuLink logo
The Web-to-App Discount Flow

Here is a flow worth stealing if you run paid social for an app-and-website e-commerce brand. An ad click goes to the website, no app-install hurdle in the way. The user adds something to the cart. Then a message shows up: "Complete this purchase in our app and get 10% off." The discount CTA hands the user to the app with the cart intact, the purchase happens in-app in the same session, and the discount applies.

One click, one discount, one completed sale. The ad walks away with an install and a purchase, both attributed back to the campaign that paid for them.

Below is exactly how it works, what it needs from your ad setup, and where most DIY builds of this flow quietly break attribution without anyone noticing.

Why website-first

The ad still sends people to your website, no app store, no "install to continue" wall. That protects click-to-landing conversion rate, which app-store-first funnels take a real hit on. The app only enters the picture once there is genuine purchase intent, meaning something is actually sitting in the cart.

That has a campaign-setup consequence people get backwards constantly. Meta's App Install campaign objective cannot route through a website first, full stop. That objective sends the click straight to the App Store or Play Store, or opens the app directly. If your funnel needs a web step before the store, the campaign destination has to be Website, run as a Traffic or Conversions objective, not App Install. Meta labels this pattern "web-to-app" and treats it as a different animal from a direct App Install ad.

Optimize the campaign toward a web-tracked event through Pixel or CAPI: Purchase if you also sell on the website, or a strong proxy like Initiate Checkout. One thing to avoid: do not set the optimization event to an App Event on a website-destination campaign. Meta's own guidance flags this as creating conflicting attribution claims between the web and app sides. The in-app purchase still gets reported back to Meta, just through a separate mechanism covered below, and it is not what this particular campaign optimizes against.

The discount pays for this purchase, not the next one

That is the real difference from a generic "download our app" nudge. The offer only pays out if the sale closes in-app, in the same session, through a deferred deep link that carries the cart and session state through the app-store detour and drops the user straight into checkout on app open. Nothing here is left as abandoned intent, and nothing depends on someone remembering to come back later. The discount buys a conversion, not a loyalty gesture.

Most write-ups of this flow go vague right here, so it is worth being precise. The exact mechanism is what decides whether the eventual purchase gets attributed correctly at all.

Two separate links are needed, not one.

Link A is the ad's destination and routes to your website. When Meta serves the ad, it appends fbclid to this URL on click. This is the actual ad click, and it is where the original click ID comes from.

Link B fires from the in-cart discount CTA and routes to the App Store or Play Store, with deferred deep linking preserving the destination through the install. It has to carry the cart contents and the original ad's fbclid forward, so the eventual in-app purchase can still be traced back to the ad that started the whole thing.

Ad click → Link A (fbclid appended by Meta) → website
  → user browses, adds to cart
  → CTA: "Continue in app, get 10% off" → Link B
     (carries cartId + the persisted fbclid)
  → app not installed → store → install
  → first open: deferred deep link delivers cartId + fbclid to the app
  → user completes purchase in-app
  → purchase event fires → forwarded to Meta CAPI with the original fbclid
  → attributed to the ad that started the journey

The part that actually needs building is getting fbclid off Link A's landing page and onto Link B's URL, surviving however much browsing happens in between. In practice that is a URL query parameter passed forward the moment the CTA is clicked, appended to Link B alongside the cart ID.

Why a pixel alone will not carry this

A Pixel plus App Events SDK cannot run this flow on its own. Carrying the cart and click ID across the app-store detour is exactly what a properly built smart link does: capture the incoming click's parameters at click time, then replay them to the app after install, matched server-side, with no clipboard hacks and no reliance on IDFA. Once installed, the app resolves the deferred deep link, pulls the cart back up, and fbclid travels along with it, so the eventual purchase can be matched back to the original ad click when it gets reported to Meta.

The DIY version of this flow usually breaks in a predictable spot. The obvious approach is a customer-written script that reads fbclid off the landing URL and stashes it in a cookie for reuse when the CTA fires. It works, but it is fragile in a way that does not announce itself. The param has to survive as a literal fbclid all the way to Link B, not get renamed to something like original_fbclid somewhere along the way, and that alone decides whether the eventual purchase gets attributed at all. Get it wrong and nothing breaks visibly. No error, no failed request, nothing that shows up in a dashboard. The purchase just quietly stops being credited to the ad, and weeks later the ROAS on that campaign looks worse than it should, with no obvious cause.

A link platform that already tracks the click, the cart, and the install in one system removes that failure mode. The click ID and cart context ride the same deferred deep linking and query-parameter passthrough mechanism, instead of a second, hand-rolled cookie sitting alongside it.

Closing the loop with Conversions API

Once the in-app purchase fires, it has to get back to Meta server-side rather than through a client SDK. iOS's App Tracking Transparency and IDFA restrictions, plus browser tracking-prevention, have made that client-side path progressively less reliable, which is the whole reason CAPI exists.

A server-to-server call goes to Meta with the same fbclid captured at the original ad click, plus the purchase value. Meta's optimization algorithm gets a clean signal about what actually converted, regardless of what happened to tracking on the user's device between the click and the purchase.

Put simply: the ad's destination is a link. The link captures the click, guaranteed, since it is the literal destination URL. The user converts through whatever path, website or app. The purchase gets forwarded to Meta's Conversions API with the original click ID attached.

Whether it is worth it, and what it does to ROAS

This version tends to pencil out better than a "buy on web, install later" flow, or a cold App Install campaign, for a few reasons. It closes in a single session, so there is no gap between the discount ask and the payoff, and no discount getting funded that never converts. The discount cost is tied to a completed sale rather than a bare install, which protects margin. CAPI feeds the completed purchase back to Meta for reporting, remarketing, and lookalikes, so even though the campaign optimizes on a web-side event, nothing about what happens after the store hop goes unmeasured. And the ad walks away with two outcomes that are each hard to get on their own, a new app user and a paid transaction, from one interaction, rather than chasing them separately, both attributed back to the link that started it.

The trade-off is real. Gross margin on that order takes a hit from the discount, so measure ROAS post-discount, not against list price. Even so, an install that arrives already attached to a completed purchase and real product intent is a fundamentally better cohort than a cold install. That is where the long-run ROAS gain shows up, through retention and repeat purchase from that app base.

How this compares to a plain App Install campaign

These solve different problems, and it is worth being honest about the trade-offs on both sides.

A plain App Install campaign has lower friction to a raw install: one tap to the store, no web step to leak users along the way. It is built for scale and top-of-funnel reach, and usually the cheaper route to volume. On iOS, optimization leans on SKAdNetwork or AdAttributionKit, privacy-preserving but coarse, delayed, and thin on smaller campaigns. And an install here says nothing about purchase intent. Someone is paying for a download, not a proven buyer.

The web-to-app discount flow adds a step, so some users drop off before ever reaching the store. That leakage is real and worth measuring rather than assuming away. In exchange, the signal is richer and faster, click capture plus CAPI, and it does not depend on ATT consent at all. Every install this flow produces already comes with a completed purchase attached, a fundamentally different cohort than a cold install. It does need the click-ID-continuity plumbing described above, more setup than flipping on an App Install campaign, though a link platform with deferred deep linking and CAPI built in removes most of that work.

Most mature e-commerce teams end up running both, aimed at different jobs. App Install campaigns handle broad prospecting and top-of-funnel reach. This web-to-app flow gets pointed at warmer or retargeted audiences where the install specifically needs to arrive attached to a sale. Neither flow should be asked to do both jobs at once.

Every piece of infrastructure this flow needs is live today. Smart, device-aware routing handles both links, web for Link A and app-or-store for Link B. Deferred deep linking uses server-side matching with no clipboard or IDFA dependency, and works through the install gap. Query parameter passthrough carries the cart ID and fbclid from Link B's click into the app on first open. Meta Conversions API dispatch, live since August 2026, fires automatically when the in-app purchase gets tracked, using the click ID captured at Link B.

One piece is worth calling out honestly: today, carrying fbclid from Link A's landing page forward to Link B still takes a small integration step on your website, persisting the value from the landing URL, then appending it to Link B's URL when the discount CTA fires. A one-line SDK helper for this sits on the roadmap. Until then, it is a handful of lines of JavaScript, not a custom backend build.

Net

One click, one discount, one sale, and a much more valuable install than most install campaigns ever produce, attributed all the way back to the ad that paid for it.