Skip to content
befday
Esc
navigateopen⌘Jpreview
On this page

Merchant Collectibles ("Catch the shop")

A Gotcha-style collectible index where the "creatures" are befday merchants. The user scans the shop's QR (physically at the stall), the app cuts out a photo and turns it into a merchant card with a rarity tier. QR-based identification — no geolocation, no CV cost. A discovery/identity retention hook built on existing QR + voucher-campaign rails.

Status: Proposed (direction); implementation deferred
Date: June 2026
Decision: Add a collectible merchant index to apps/native, inspired by Gotcha (snap a creature → app cuts it out → identifies it → adds it to a collection with rarity tiers). Here the “creatures” are befday merchants (shops on pos). The user scans the shop’s QR — the static QR pos already displays, or a printed “catch me” sticker — then snaps a photo; the app cuts out the subject into a merchant card added to their collection. Identification is QR-only (no geolocation, no computer vision for matching — only the cosmetic subject cut-out). Merchants/befday set the rarity (common → legendary) to steer discovery.


TL;DR

A “catch ’em all” index where the creatures are befday merchants. Scan a shop’s QR (proof of presence) → snap a photo → on-device cut-out becomes a collectible card with a rarity tier. Identification is a QR → shop_id lookup in befday’s own DB, so no open-world CV and no GPS. Uncaught merchants show as silhouettes (a hunt). Reuses the shop QR, points rewards, and nearby surface; one catch per (user_id, shop_id).


Context

The retention stack covers money (points), memory (receipts), habit (nearby), and identity (birthday). It lacks a playful, completionist discovery loop — the “gotta catch ’em all” pull that makes people seek out new merchants.

Gotcha nails the mechanic for animals:

  1. Catch — point, shoot; the app segments the subject out of the photo.
  2. Collect — each catch becomes a card with a rarity (common → legendary).
  3. Index — silhouettes wait to be filled; best finds are shareable.

The insight: befday already owns a finite, real-world “creature index” — its merchant network. Unlike Gotcha (which must identify any animal via CV), befday only needs to know which of its own merchants the user is at, and it has the perfect anchor: the QR at every pos counter. That collapses open-world identification into a QR lookup. The fun (the photo cut-out) stays; the expensive part (general vision) and the fragile part (geolocation) both disappear.

Composes with nearby: it adds a caught / uncaught state per merchant, turning the map into a hunt.


Decision

The loop

1. User is physically at a befday shop and sees the shop's QR
   (the SAME static QR pos already shows, or a printed "catch me" sticker)
2. User taps "Catch" in native → scans the QR
   → QR encodes the shop_id → instant, exact merchant match against befday's DB
3. App confirms "You found <Shop>!" and opens the camera
4. User snaps a photo (storefront, product, their food…)
5. App segments the subject out of the photo (on-device cut-out)
6. The cut-out becomes the artwork on the merchant's CARD
   → card carries: merchant name, the user's cut-out photo, rarity tier, caught date
7. Card is added to the user's collection / index
8. Uncaught merchants appear as silhouettes (in nearby + the index) → the hunt

A verified paid visit (Decision 01) can also auto-unlock the catch without scanning — see “Catch trigger” below. But the QR scan is the simple, universal path: it works for any stall, with or without a transaction, and needs no address and no GPS.

Two halves, deliberately separated

Half What it is How it’s done Cost / risk
Identification “Which merchant is this, and am I allowed to catch it?” Scan the shop’s QR (or auto via a paid visit) ~zero
Cut-out “Turn my photo into a sticker” On-device subject segmentation ~zero

The catch is authorized by the QR (or the visit), not by the photo. The QR proves physical presence; the photo is just souvenir art. So there’s no fraud surface in image recognition, no dependence on addresses or GPS, and the photo can be anything (their meal, the sign, themselves).

Catch trigger & identification — scan the shop’s QR (chosen)

The merchant is identified by scanning a QR physically at the shop. The QR encodes the shop_id, so the match against befday’s own DB is exact and instant — no addresses, GPS, or CV.

Two QR sources, in priority order:

  1. The existing pos QR. pos already shows a “scan to identify” QR for the Stamp Identification Flow. The catch flow reuses it — one scan can link the customer and unlock the catch. Zero new hardware.
  2. A printed “catch me here” sticker. For stalls that don’t surface the POS QR, befday issues a cheap printed QR (table tent / window sticker) tied to the shop_id. Works for kampung stalls, night-market stalls, and shops with no address.

Scanning a physically-present QR is itself proof of presence — you can’t catch a shop you’ve never stood in front of.

Auto-catch on a paid visit (no scan needed): a phone-identified paid order (the same event that issues a purchase stamp in Decision 01) can auto-unlock the shop as catchable. A convenience layer on top of QR, not a replacement.

Why not geolocation? It was the original plan but it’s fragile: many stalls have no usable address, GPS drifts indoors/in malls, and geofences are easy to spoof. A QR at the stall is simpler to build, simpler to explain, and works everywhere — so geolocation is dropped entirely.

Cut-out — on-device subject segmentation

The one genuinely new piece of tech, and it’s cheap and offline:

  • iOS: Vision VNGenerateForegroundInstanceMaskRequest (lift subject from background) — on-device, free.
  • Android: ML Kit Subject Segmentation — on-device, free.
  • Fallback: ship without auto cut-out (raw photo framed in a card), add segmentation later.

The cut-out is cosmetic, not load-bearing — a poor segmentation never blocks a catch.

Rarity — merchant / befday set (chosen)

Each merchant card has a rarity tier that befday or the merchant configures:

Tier Example use
Common Everyday merchants — easy to catch, fill the index
Rare Newer or lower-traffic merchants befday wants to push
Epic Limited-time pop-ups, events, seasonal stalls
Legendary Flagship partners, special collabs, “catch this month” challenges
  • Rarity is a discovery lever: befday makes the merchants it wants visited more desirable to collect. This is the monetizable/strategic angle (a merchant can pay/partner for a higher tier or a “featured legendary” slot).
  • Rarity could later be auto-derived (rarer = fewer users have caught it) as a secondary signal, but the set model gives befday control for cold-start and promotions. (See Cold-Start.)

Collections & sharing

  • Index view: all befday merchants as cards; caught ones show the user’s cut-out art, uncaught ones show a silhouette.
  • Collections / sets: group by category (cafés, bakeries…), by area, or by curated “challenges” (“catch 5 legendary this month → bonus points”). Completing a set can grant points — reusing existing reward rails, mirroring how the birthday engine grants via the same wallet.
  • Sharing: the cut-out card is inherently shareable (it’s a nice sticker of their photo) → a built-in growth/referral surface, like the year-in-review in insights.

Why this fits befday specifically

Gotcha’s hard problem befday’s version Result
Identify any animal on earth (CV) Scan a QR → exact shop_id in your own DB Trivial, free
Anti-cheat on “did you see it?” QR is physically at the shop (or verified visit) Already solved
Populate a creature index Index = your merchant DB You own it
Make rare creatures exciting Merchant-set rarity as a promo lever Monetizable

It also reframes a cold-start liability into an asset: uncaught silhouettes give a new user in a sparse area something to aspire to (a hunt), where an empty list would just feel dead — directly addressing the emptiness problem in Cold-Start & Coverage.


Relationship to existing native features

  • vs Bookmarks: bookmarks = “shops I want to use” (intent, forward-looking). Collectibles = “shops I’ve proven I visited” (trophy, backward-looking). Complementary — bookmark to plan the hunt, catch to record it.
  • vs Nearby: nearby gains a caught/uncaught annotation per merchant; “uncaught nearby” becomes a ranking factor and a push trigger (“a legendary you haven’t caught is 200m away”).
  • vs Stamps: the catch reuses the same shop QR that powers stamp identification. One scan can link the customer, issue a stamp, and unlock a catchable card.

Data Model Impact (sketch)

Mostly new, but small and self-contained. Reuses store_customers / shops for identity and visit proof.

Table / column Notes
shops.collectible_rarity enum common|rare|epic|legendary — merchant/befday-set card tier
shops.collectible_enabled boolean — is this shop catchable at all
merchant_catches new — one row per caught card: (user_id, shop_id, image_url, caught_at), unique (user_id, shop_id)
merchant_catches.image_url the user’s cut-out photo (stored in object storage; only the user’s own art)
collectible_sets / set_members optional — curated challenges (“catch 5 cafés”); set → reward (points) on completion
  • Catchability is derived, not stored: a shop is catchable for a user once they scan its QR while it’s collectible_enabled (a paid visit can also auto-unlock it). One catch per (user_id, shop_id) — enforced by the unique constraint (idempotent, like the welcome stamp).
  • Rarity is config on the shop, tunable any time (a merchant can be promoted to legendary for a campaign window).

API Impact (sketch)

Procedure Status Notes
consumer.collectibles.index New All catchable shops + the user’s caught/uncaught state (silhouettes)
consumer.collectibles.catch New Resolves a scanned QR → shop_id, records a catch (idempotent per shop); stores cut-out image
consumer.collectibles.sets New Curated challenges + progress; completion grants points via existing wallet
merchant.shops.setRarity New Merchant/admin sets collectible_rarity / collectible_enabled

The cut-out happens on-device; the client uploads the finished sticker. The server only resolves the scanned QR → shop_id and enforces one catch per shop. Same single-pass / index-the-user’s-shops read pattern as nearby.


Consequences

Type Consequence
Pro The fun of Gotcha without its hard/expensive part — no open-world CV, and no geolocation to fight. Identification is a QR scan against your own DB. Recurring cost ≈ zero.
Pro Works for every merchant, including addressless stalls — a printed QR sticker is all it takes. Composes on rails that already exist — the shop QR (Decision 01), points rewards (Decision 04), nearby surface (Decision 07).
Pro Turns the cold-start “empty list” into a hunt (silhouettes to aspire to) instead of a dead end.
Pro Merchant-set rarity is a monetizable promo lever (featured/legendary slots, “catch this month” partner campaigns).
Pro Cut-out cards are inherently shareable → organic growth.
Con It’s a new surface (collection UI, camera/cut-out, sets) — more net-new build than the read-mostly retention ideas (insights/tiers).
Con On-device segmentation quality varies by device; needs a graceful fallback (raw framed photo) so a bad cut-out never blocks a catch.
Con Image storage cost (one user photo per catch) — small, but real; needs lifecycle/limits.
Con Value scales with merchant coverage — a tiny index isn’t fun. Tie launch to the same density strategy as Cold-Start & Coverage.
Con Depends on the QR being visible to customers — merchants must surface the POS QR or display a printed sticker. A small rollout cost (sticker distribution), but far cheaper than geofencing every stall.

Open Questions

  • One QR or one per surface? Reuse the single pos identification QR for everything (link + stamp + catch), or issue a distinct “catch” QR/sticker so walk-ins can catch without the POS being involved? (Leaning: reuse, with printed stickers as the fallback for stalls that don’t show the POS QR.)
  • QR spoofing — accepted for v1. A static shop_id QR could in theory be copied and shared online. Decision: physical presence + one-catch-per-shop is enough — there’s little incentive to farm a single, non-repeatable catch, and the catch grants only a cosmetic card (plus optional set rewards). If farming ever becomes a real problem, pos can emit a short-lived/rotating code and we add scan-rate limits — but not in v1.
  • One catch per shop, or re-catchable? Re-catching (update your sticker on a later visit) adds replay value but complicates “completionist” semantics. (v1: one per shop.)
  • Set rewards vs balance: do completed sets grant points, a perk, or just a badge? (Reusing points is cheapest.)
  • Rarity governance: who can set legendary — merchant self-serve (paid), or befday-curated only — to keep tiers meaningful?
  • Photo moderation: user-supplied images need basic abuse handling even though they’re private-ish; what’s the policy if a card is shared publicly?
  • Cut-out fallback UX: when segmentation fails or the device lacks it, is the raw photo acceptable, or do we offer a manual lasso?

Was this page helpful?