Work Functions · Custom app
Dynamic discounts
A public Shopify app that makes Google's automated discounts actually apply at checkout, as a Shopify Function.
- Client
- Informatica · published on the Shopify App Store
- My role
- Sole developer
- Period
- 2024 — 2025
| Distribution | Shopify App Store (public) | |
|---|---|---|
| Discount surface | Shopify Function — Discounts API | |
| Locales | en / uk / ru | |
Problem
Google's automated-discounts programme sets a per-product sale price for Shopping ads, but Shopify has no built-in way to honour that price in the cart. The discount shows in the ad and then disappears at checkout.
Constraints
A public app has to pass App Store review — billing, GDPR webhooks, a privacy policy, minimal scopes. The discount logic runs inside a Shopify Function, compiled to WebAssembly with a tight execution budget.
Hard part
Getting the per-line discount amount into the Function reliably, given Google puts it in the product feed rather than anywhere Shopify exposes cleanly.
Stack
- Shopify Functions
- Remix
- Polaris
- App Bridge
- Prisma
- Fly.io
Links
What the Function does
On every cart evaluation the Function walks the line items, reads a discount
amount for each — from a line attribute if it’s there, otherwise parsed out of
the product title where the feed puts it — and returns a fixed-amount discount
per line. It runs under the Discounts API’s purchase.product-discount.run
target, with unit tests against the input query and a WebAssembly build small
enough to stay inside the execution budget.
The app around it
The Function needs configuration a merchant can set — start and end dates,
whether the discount stacks with others — so there’s an embedded admin screen
built with Shopify’s discount-app components, storing its settings in a
function-configuration metafield. The rest is the unglamorous half of a public
app: OAuth, billing, the mandatory GDPR and app/uninstalled webhooks, a privacy
policy, and only the write_discounts scope so review has nothing to query.
Why it’s small
It does one thing. The temptation with a public app is to add a dashboard and analytics and settings nobody asked for; this one stays a Function plus the one screen that configures it — which is also why it passed review without a fight.