How Forage fits your stack.
A customer points a camera at your packaging and pays. This page is the rest of it: what resolves, what syncs, whose Stripe account takes the money, and what a shopper sees when a piece of it fails.
Written for whoever has to draw the diagram before anyone signs anything. It is the mechanics and the limits, not a pitch. If you want the argument for install-free checkout before the plumbing, start with one-tap checkout is already the default.
A scan resolves to a URL, and that is the whole trick
The code you print encodes a short link on a Forage domain, with two path segments: the brand and the link. Our own demo code resolves to /litt/13011017. Nothing about the destination is fixed by the ink. The printed pattern points at a redirect we control, so the product a can sends people to can change after the can is on a pallet.
What happens next depends on the phone, and you do not get to choose which path a given customer takes:
- On iOS, where the App Clip is registered for that URL, iOS treats it as a universal link, shows the App Clip card, and runs the clip. No App Store visit, no install.
- Everywhere else — Android, older iOS, a phone with App Clips switched off, anyone who taps the link out of a message — the same URL loads the mobile storefront in the browser.
Both paths land on the same thing: the product, its images and copy from your catalogue, a quantity control, and a wallet button. Apple Pay is offered through Stripe's payment request flow when the device and browser actually support it, and the button stays hidden when they do not, rather than being shown and broken. Confirming with Face ID returns a payment token plus the name, contact details and delivery address the wallet already holds. Nobody types an address.
The order that comes out the other side carries a customer, not just a card. Once the payment succeeds the buyer is attached to the order as a Shopify customer, which is what makes the loyalty side possible at all: points accrue against the brand that was bought from, and a first-time scanner becomes someone you can recognise on the second scan.
Shopify stays the source of truth
You connect a store once, with a Shopify Admin API token. Forage imports the catalogue in bulk at that point, then keeps it current with webhooks rather than polling. Sixteen topics are subscribed at connection time, covering products, product listings, orders, delivery profiles and shop details.
| What | Direction | How |
|---|---|---|
| Products, variants, prices, images | Shopify to Forage | Bulk import on connect, then products/create, products/update, products/delete |
| What is published | Shopify to Forage | product_listings/add, update, remove |
| Delivery profiles and rates | Shopify to Forage | profiles/create, update, delete, plus your shipping zones |
| An order placed through Forage | Forage to Shopify | A draft order is created at checkout and completed as paid |
| The customer on that order | Forage to Shopify | Attached once the payment succeeds |
| Order state afterwards | Shopify to Forage | orders/paid, updated, edited, fulfilled, cancelled, delete |
| Shop details | Shopify to Forage | shop/update |
The row that matters most is the fourth. A Forage sale is a Shopify order, not a report you reconcile at month end. It appears in your admin, in your Shopify reports, and in whatever you already have hanging off orders/paid — your 3PL, your accounting export, your post-purchase email. Nothing downstream has to learn about us.
Prices are recomputed on the server
The basket a browser sends is a request, not an instruction. The server prices it again from your catalogue and will not create a payment for less than that figure. Worth saying out loud, because the alternative — trusting a total posted from a phone — is a category of fraud you should never have to think about, and it is the kind of thing an agency is right to ask about before recommending anyone.
One limit to know before you design a campaign: a basket can hold products from one brand only. A payment is created on one brand's account, so a mixed basket is refused rather than split.
Without Shopify you get a storefront, not yet a checkout
This is the part most vendor pages leave vague, so here it is flatly. Before Forage will take money on a brand's behalf, three things have to be true at once, and they are checked on the server on every attempt:
A connected Shopify store
An Admin API token and a shop name. Without them there is nowhere to write the order, and taking the payment anyway would mean money captured against nothing.
A Stripe account that can take charges
Connected and finished. An account that was started but never onboarded, or unlinked later, counts as not ready. Holding an account id is not the same as being able to charge on it.
At least one shipping zone
A brand with no zone cannot price delivery, so the order cannot be completed honestly.
If any of the three is missing, the storefront still works — the products, the images, the copy, the code that got you there — and the buy button is replaced with a line telling the shopper this brand is not taking orders through Forage yet. The button is hidden in the browser for politeness; the check that counts runs on the server, so a hand-crafted request fails in exactly the same place.
What that means in practice: if you are not on Shopify you can have pages, codes, links and scan data today, and you cannot have checkout today. If taking money this quarter is the point of the project, say so on the first call rather than the fourth. It changes the answer.
The money lands in your Stripe account, not ours
The payment is created directly on your own connected Stripe account. Forage's share is an application fee taken out of that charge, set per merchant — not a separate invoice, and not a deduction made somewhere in the middle where you cannot see it.
Three things follow, and they are why the arrangement is worth caring about:
- The charge is yours. It sits under your account, with your descriptor, in your Stripe dashboard, alongside every other payment you take.
- Refunds and disputes are yours to see and to answer, in that same dashboard, on the same timelines, with the same evidence tools. You are not waiting on us to forward a chargeback notice.
- Payouts run on your schedule to your bank. There is no float sitting with Forage.
Mechanically, that is what the phrase "merchant of record" usually turns on. If the phrase matters to your finance team, and for VAT treatment it generally does, get the answer in writing as part of the contract rather than taking it from a web page, including this one.
Card details go from the customer's device to Stripe. The storefront receives a token and never sees a card number.
An App Clip removes the browser, not the checkout
An App Clip is a small slice of an iOS app that Apple launches from a code, a tag or a link with no App Store install. What it adds over a good mobile page is narrower than most write-ups suggest, and worth stating precisely:
- It launches into the product, not into a page load. Native rendering, no browser chrome, no cold start of a web view.
- Notifications for up to 8 hours after each launch, with no permission prompt.[2] For someone who has just scanned a can and has never given you an email address, that window is the only re-contact route in existence.
- Apple Pay is there immediately — though Safari gets Apple Pay too, so this alone is not the reason to build one.
What it costs is a real app. An App Clip is a build target inside a full iOS app, reviewed and shipped with it; there is no App Clip-only product. So either you are building and maintaining an iOS app, or you are using a platform that already has one. With Forage it is the second: the clip is ours, and your links are registered against it. The domain association file that lets iOS claim those URLs is served from the storefront domain.
Two constraints then shape everything downstream. The first is size, and two things set it rather than one. A code on packaging is a physical invocation, which rules out Apple's 100 MB tier outright, because that tier is for digitally invoked clips only. What you are left with is set by your minimum deployment target: 15 MB if you require iOS 16 or later, 10 MB if you support anything earlier.[1] So the 100 MB number is real and almost certainly not yours, and supporting iOS 14 costs you a third of the budget. The second constraint is Android, which has had no install-free native runtime since Google withdrew Play Instant in December 2025,[3] so the printed code has to work as a web page for the larger half of the market. Both are worked through in App Clips, explained for Shopify brands. The short version: the web path is not the fallback, it is the floor, and we build it first.
What breaks, and what a shopper sees when it does
Anyone evaluating a vendor properly wants this section, and most vendors do not write it. Printed codes make it sharper than usual, because the artefact in the customer's hand cannot be redeployed.
| What breaks | What the shopper sees | What you do |
|---|---|---|
| Shopify token revoked or expired | The storefront loads and browses; checkout is disabled with a named message | Reconnect the store. Nothing reprints. |
| Stripe account unlinked or half-onboarded | The same | Finish onboarding in the dashboard. |
| No shipping zone | The same | Add a zone. |
| Product deleted in Shopify | The link resolves; the product is gone | Repoint the link at a live product. |
| Campaign retired | The short link stops resolving | Repoint it. The printed code is a redirect, not a destination. |
| Phone with no App Clip support | The mobile storefront, in the browser | Nothing. This is the designed path, not a degraded one. |
| Basket with two brands in it | Refused before payment | Nothing. One basket, one brand, by design. |
The failure we care most about is the silent one
Money captured and no order created. A shopper is charged, their bank confirms it, and nothing ever arrives — and the brand finds out from the complaint. That is why the readiness check runs before a payment can be created rather than after it, and on the server rather than in the browser. It is the least interesting thing on this page and the one we would defend hardest.
What we will not claim without a measurement design
We will not tell you Forage lifted your conversion rate by some percentage. Scans are not orders, and orders after a scan are not orders caused by a scan. Some share of what any dashboard would hand us is people who were going to reorder anyway, through a channel you already pay for. That is cannibalisation, and it is the default outcome unless the test was designed against it.
What we will do is agree, before anything is printed, what is being compared with what, over what window, and what else is changing at the same time. The method is written up in how to prove one-tap actually worked, published before we had anything to prove with it, which is the right order to do it in.
The same rule runs backwards. You will see "apps convert three times better than mobile web" quoted across this category. It traces to 2018 research comparing people who chose to install a retailer's app against everyone else, which is a comparison of customer loyalty dressed as a comparison of technology. We take it apart in one-tap checkout is already the default rather than repeat it here.
Every term on this page is defined, once and properly, in the glossary.
Sources
- Apple, Maximum build file sizes — the App Clip size tiers, and the digital-invocations-only condition on the largest one. Primary ↩
- Apple, Enabling notifications in App Clips — the 8-hour ephemeral notification window and the key that opts into it. Primary ↩
- Google, Google Play Instant — deprecation notice: from December 2025 instant apps cannot be published and the Instant APIs no longer work. Primary ↩