Product docs
Freebee end-to-end flow
Last updated Oct 23, 2026 · @praveen · 12 sections
Who does what, in what order, from an advertiser signing up to the report the next morning. After the main flow: the links and logins, the metrics we collect, the booking flow, bidding for busy windows, what happens when something fails, OTP and coupons, upload rules, where AI fits, the native player for Android, Windows and Mac, and how we talk to the advertiser. Anything marked proposed is not built yet.
The flow
Ops can add and pair screens at any time; an ad only reaches the wall once it is approved and booked. The highlighted boxes are the Hit for Six loop in the mall: the wall shows a QR code, the shopper gets a code on their phone, enters it at the kiosk, rolls the dice ball by ball, and a prize lands in their phone wallet. The camera and the play record count everything, and both the advertiser's report and the ops Today page fill in the next morning.
Links
Everything runs at https://freebeeads.com. The demo campaigns are booked on the screen "Escalator Court — North Portrait".
| Page | Link | Who |
|---|---|---|
| Sign in | https://freebeeads.com/login | everyone |
| Sign up with your own email | https://freebeeads.com/signup | advertisers |
| Advertiser Home, Campaigns, Creatives, Reports, Book | /dashboard · /campaigns · /creatives · /reports · /book | advertisers |
| Create a game ad | https://freebeeads.com/creatives/game/new | advertisers |
| Ops Today, Screens, Bookings, Approvals, Footage, Devices | /ops · /ops/screens · /ops/bookings · /ops/approvals · /ops/footage · /ops/pair | ops |
| The wall (player, shows a pairing code) | https://freebeeads.com/player | one laptop or TV per screen |
| Kiosk beside the wall | https://freebeeads.com/kiosk/ba1be657-dab3-4281-94ac-29a3c512e084 | a tablet |
| Phone join page (what the wall's QR opens) | https://freebeeads.com/play/ba1be657-dab3-4281-94ac-29a3c512e084 | any phone |
| Shopper's coupon wallet | https://freebeeads.com/w | any phone |
Logins: demo advertiser demo@dooh.local / demodev123; ops ops@dooh.local with the ops password shared one to one. Friends can also sign up with their own email (password of 8 characters or more, plus a business name). There is no password reset yet.
Metrics we collect
Every number comes from one of three sources: the play record written by the screen, the camera on the screen, or the game itself. Nobody is identified; the camera keeps counts only and the phone number of a wallet user is stored encrypted and never shown to an advertiser.
| Metric | Comes from | Shown where | When it is missing |
|---|---|---|---|
| Plays | the screen writes a play record when an ad finishes | Delivery band on Home, campaign report, ops Today and Metrics | screen off or unpaired: plays stop; the Delivery band shows 0 and ops Today raises an "offline" alert |
| Opportunity to see (walked past) | camera on the screen, person count while the ad played | Audience band, attention funnel | camera off: the band shows clearly labelled sample numbers and says the screen is not counting yet |
| Watchers | camera, faces turned to the screen for 1 s or more | Audience band, watchers by day and by hour | same as above; a face-only camera counts watchers but not passers-by, so the attention rate shows a dash with a note |
| Attention (seconds) | camera, how long each watcher kept looking | Audience band, by-creative table | same as above |
| Age bands and gender | camera, estimated on the screen itself, counts only | campaign report | same as above |
| Scans, codes, innings, balls, runs, prizes | the cricket game: phone page, kiosk, wall | Engagement band, Hit for Six funnel, innings CSV | no game ad in the range: the band collapses to one line with "Create a game ad" |
| Rounds, completions, QR code scans | spin, wheel and catch games | Engagement band, game funnel | same |
| Coupons issued, claimed, redeemed | the phone wallet | Engagement band, ops Wallet page | none issued: dashes |
| Spend and revenue booked | bookings | Value band, ops Value band, Bookings | none: ₹0 |
| Last check-in, held batches | the screen's status call and the play record upload | ops Screens health, ops Today alerts | not reported: "Not seen lately", then "Offline" |
Numbers land in the dashboards the next morning for the previous day; Live right now and Playing now update every 5 seconds.
Booking flow
There is no bidding: every screen has a fixed rate per slot per day set by ops, and an hour window costs its share of the day. A game ad holds its window exclusively (one brand on the wall at a time); a video or image ad shares the loop. The booking can be cancelled before it starts and future dates are freed; a booking that has already played cannot be cancelled from the portal.
Bidding for busy windows
Today every window is first come, first served at the fixed rate, which is right for most screens and most days. On a main screen on a busy day (weekends, Diwali week, a mall event) several brands will want the same evening hour, and the first click should not decide it. The proposal keeps the fixed rate as the floor and adds a short, sealed bidding round only where ops turn it on.
| Rule | Proposed setting | Why |
|---|---|---|
| Where it applies | ops flag a screen plus a date range as "busy"; one toggle on the screen's page | keeps the rest of the network simple |
| Floor | the screen's fixed rate for that window | nobody pays less than today |
| Bids | one per advertiser per window, at or above the floor, in steps of 10%; an optional maximum that auto-raises in steps when outbid | fair, no bid wars in real time |
| Visibility | the current highest bid is shown; who placed it is not | pressure without poaching |
| Close | 48 hours before the window starts; late entries are not accepted | leaves time for approval and a make-good |
| Award | highest bid wins and pays its bid; a tie goes to the earlier bid; the ad must already be approved, otherwise the next bidder wins | no empty wall on the busiest hour |
| Everyone else | pays nothing; offered the next free window on that screen or the same hour on another screen in one tap | a loss still ends in a booking |
| Video and image ads | a bid buys extra slots in the loop (share of voice) instead of exclusivity, since loop ads share the hour | the wall is only exclusive for game ads |
| Guard rails | one brand may hold at most three consecutive busy windows on a screen; ops can cancel a round and fall back to the fixed rate | protects variety for shoppers and the mall |
What the advertiser sees: the hour grid marks busy windows with the floor and the current high bid, and the booking summary rail shows "Bid ₹X, closes Fri 18:00" instead of a fixed price until the round closes. Ops see the open rounds on the Bookings calendar with the bidder count. Messages on close go out through the channels in "How we talk to the advertiser".
When things fail
The rule behind all four rows: a number that was never measured shows as a dash or a labelled sample, never as zero, and a play that was never recorded is never billed. The gap today is reach, not detection: ops only learn about an offline screen when they open Today, and the advertiser only when they open Home. The proposed push messages in "How we talk to the advertiser" close that gap.
OTP and coupons
The one-time code is the only moment we ask a shopper for anything personal, and only because the coupon has to live somewhere they can find again. The number is kept as a hash plus an encrypted copy, used for nothing else, and a shopper can erase their wallet from the /w page. Codes are minted on the server and expire in minutes.
What is not connected yet: the SMS or WhatsApp sender. On the test site the code is shown on the page itself so testers can continue. Before launch, delivery goes through WhatsApp Cloud API with SMS as the fallback, and the test shortcut is switched off. Daily prize budgets per tier ("max wins per day") already cap how many coupons a campaign can hand out.
Upload rules
A file is checked the moment it is uploaded, before anyone sees it. A wrong file is refused with one plain sentence and nothing is saved; a file that passes goes to our team for approval.
| What | We accept | What we say when it is wrong (built today) |
|---|---|---|
| Video ad | mp4 (H.264), up to 50 MB, up to 10 seconds, portrait or square preferred | "video exceeds 50MB limit" · "video duration 14.0s exceeds 10s limit" · landscape is accepted with the warning "landscape orientation; portrait or square preferred" |
| Image ad | jpg or png, up to 10 MB | "image exceeds 10MB limit" |
| Anything else (pdf, gif, mov, webm, pptx) | refused | "unsupported file type '.mov': allowed jpg/png images, mp4 video" |
| Game ad images (logo, product shot, symbols, packs) | png or jpg, up to 5 MB; png with transparency for logos and symbols | "Image exceeds 5MB." on the slot; the slot shows an example of a good file |
| Game ad clips (background loop, win clip, ad break) | mp4, up to 20 MB | "Video exceeds 20MB." on the slot |
Proposed, not built: convert common mistakes instead of refusing them. A .mov or .webm is transcoded to mp4; a 15 s video is offered a 10 s trim with a preview; a landscape video is offered a portrait crop; an oversized image is resized. The message then reads "We converted your file to the screen's format; check the preview" with a side-by-side before and after.
AI in the flow
What AI would do for an advertiser: take a phone photo of a product and return a clean, upright, 9:16 image with the background removed; turn a 10 second video into a mock-up of how it looks on the wall; suggest three headlines from the brand name and the product. Each suggestion is shown beside the original and the advertiser picks; nothing is applied silently, and our team still approves the final ad.
What AI would do for the wall: catch the names the block list misses, such as slang spelt in English letters, a brand or a real person's name used as a joke, or a mixed Telugu and English phrase. The block list stays as the first, instant check; the AI check runs in under a second behind it. A blocked name always gets the same message as today, and nothing typed is kept beyond the innings.
The game footage itself (bowling, batting, the dice) is generated once by us and shared by every cricket campaign; sponsors add their packs and logo on top. A proposed extension is a per-brand pack render, so a new sponsor's pack appears on the shelf without a designer.
Native player instead of a browser
A browser tab works for a demo but fails in a mall: it needs someone to open it, it can be closed or navigated away, it cannot start on boot, it loses the camera permission after a reboot, and a wifi drop stops the loop. The app wraps the same web engine (one codebase, the same play record format), so the server and dashboards do not change and the browser player keeps working for tests.
| Platform | Device in the mall | Packaging | Camera | Notes |
|---|---|---|---|---|
| Android | Android TV box or a signage box behind the wall, or an Android tablet as the kiosk | APK, side-loaded or via a managed store; device-owner kiosk mode | USB or built-in camera; counts on the device | cheapest hardware; first to build |
| Windows | mini PC driving the LED wall | MSI installer, runs as a service, assigned-access kiosk mode | USB webcam | common for LED controllers |
| Mac | Mac mini driving the wall | DMG, launch agent, auto-login | USB webcam | your test setup today |
What the app does that the browser cannot: start itself after power loss, keep playing from its cache for hours offline and upload the queued play records afterwards, restart the engine if it stalls, pull engine updates in the night, and report its health (temperature, disk, camera) in the check-in. Pairing stays the same six-character code shown on the screen and entered in Ops, so nothing changes for the ops person. Build order: Android first (one app covers the wall box and the kiosk tablet), then Windows, then Mac.
How we talk to the advertiser
Today every message lives inside the dashboard: a status badge, an alert strip, or a note under a number. Nothing is sent to the advertiser's phone or email yet, so an advertiser who does not open the site does not hear about an approval or an outage. The proposed channels add WhatsApp first (the market's default) and email as the record.
| Event | Built today (in the dashboard) | Proposed (push) |
|---|---|---|
| Ad approved or rejected | badge on Creatives and Campaigns; rejection reason on the card | WhatsApp: "Your ad Diwali Sale is approved and will play from 2 Nov" or the rejection reason with a link to fix it |
| Booking confirmed | success card with three next steps | WhatsApp plus an email receipt with the invoice |
| Payment pending or received | badge on the campaign | WhatsApp reminder two days before the start; receipt on payment |
| Screen offline during your window | Live right now shows "Nothing playing"; ops Today raises the alert | WhatsApp to ops immediately; to the advertiser after 30 minutes with the make-good (plays credited or extended) |
| Camera not counting | Audience band shows sample numbers with a note | nothing to the advertiser; ops alert only |
| Your campaign started, ended, report ready | badges; report fills next morning | morning WhatsApp with the four headline numbers and a link |
| Prize claimed by a shopper | counts in the Engagement band | none (shopper gets the coupon; see OTP and coupons) |
Ops are told the same way today: alerts on Today and badges on Approvals. The proposed ops channel is a WhatsApp group fed by the same alerts, with offline screens first.
What is still missing
The flows above are the product. A mall-screen business needs the pieces below too, and most of them are not started. Ordered by what blocks a real paying launch first.
| Area | Gap | Status | Needed for |
|---|---|---|---|
| Payments | no online payment; ops marks bookings paid by hand; no invoice with GST; no refund or credit for cancelled or missed plays | Not started | first paid campaign |
| Secrets and launch switches | rotate the Railway database password, secret key and ops password; switch off the test OTP mode; set a real domain and email sender | Not started | launch |
| Account basics | no password reset, no team members or roles, one ops account for everyone, no company profile beyond a name | Not started | friends testing, first customers |
| Advertiser messages | approvals, confirmations, outages and reports are shown only inside the site; WhatsApp and email sending not built | Proposed | first customers |
| Legal and privacy | no terms, privacy policy or camera notice in the mall; DPDP consent wording for the wallet; data retention and delete-my-data | Not started | launch |
| Content policy | no written rules for what ads are refused (alcohol, tobacco, political, medical claims) and no mall sign-off step | Not started | first customers |
| Prize fulfilment | prizes are coupons; no stock count, no expiry reminder, no check that the counter honoured the coupon, no fraud limits per phone | Proposed | first game campaign |
| Proof of play | no camera snapshot or signed log an advertiser can audit; counts are trusted from the screen | Not started | larger advertisers |
| Mall partner side | no mall login, revenue share report, holiday hours or maintenance mode per screen | Not started | second mall |
| Device reliability | browser player only; no auto-start, offline cache, remote restart or health report (see Native player) | Proposed | any unattended screen |
| Support and incidents | no support inbox, no runbook for a screen down at 7 pm, no uptime alerting on Railway or Vercel | Not started | launch |
| Languages | portal and phone page are English only; Telugu and Hindi for the shopper pages first | Not started | shoppers |
| Accessibility and sound | no audio on the wall yet; kiosk has no large-text or colour-blind mode | Proposed | later |
| Scale | one time zone, one currency, one city; screens have no group or region | Not started | second city |
| Analytics on ourselves | no funnel on sign-up to first booking; no error tracking in the browser | Not started | growth |
| Backups | Railway Postgres backups and media-volume backups not confirmed; no restore drill | Not started | launch |