The affiliate marketplaceFive retail partnerships, a curated catalogue with CLIP vectors, and a recommendation engine that knows how much it knows about you.
- 1WRDB's revenue model is affiliate commerce: recommend a product that fills a gap in someone's wardrobe and earn a commission when they buy it. I ran the affiliate side end to end, from the network applications and the programme partnerships to the feed pipeline, the catalogue and the scoring engine that blends discovery with personal taste by a continuous richness score.
- 2Role: Co-founder: the affiliate side, end to end. Status: Live.
- 3Stack: Awin, Supabase, pgvector, CLIP, gpt-4o-mini, Python, Swift.
- 4Key figure: 298 products live, from five Awin programmes.
Recommend, do not sell
A wardrobe app knows something a shop never does: what the user already owns. WRDB's business model turns that into affiliate commerce. The app recommends a product that fills a real gap in the wardrobe, the user taps through to the merchant on a tracked link, and the network pays a commission on the sale. Nothing is stocked, nothing is shipped, and the recommendation is only worth showing if it is good. I owned that side of the company end to end: the applications to the networks, the programme partnerships, the product feed pipeline, the catalogue and the recommendation engine's design and SQL.
The partnerships came first. In January 2026 I applied to the affiliate networks with a publisher profile describing the app, its audience and the integration, and the pitch deck attached. CJ Affiliate blocked the application because a promotional property needs a live App Store link. Awin España accepted it on a refundable one-euro deposit. Inside Awin every merchant runs its own programme, so I applied programme by programme: thejewellershop.com ES joined on 29 January 2026 and activated its product feed the same day; Bonheur Jewelry, Dooers and Zapatos OBI were accepted after it; Palomo Spain is applied for. On the network's own figures the jeweller converts 16.15 percent of clicks, approves 93 percent of sales and pays 1.58 EUR per click, fifty-four days after the sale.
| Programme | Network | Status | Terms and notes |
|---|---|---|---|
| thejewellershop.com ES | Awin España | Joined 29 Jan 2026 | Feed 101788, 14,274 products; 16.15% conversion, 93% approval, 1.58 EUR per click, 54-day payment |
| Bonheur Jewelry | Awin España | Accepted | 10% commission; feed to be activated |
| Dooers | Awin España | Accepted | Feed ingested with its own script |
| Zapatos OBI | Awin España | Accepted | Feed ingested; images cropped for the flatlay |
| Palomo Spain | Awin España | Applied | 10% commission, 30-day cookie |
| SHEIN | CJ Affiliate | Blocked | A promotional property needs a live App Store link |
From feed to catalogue
A joined programme unlocks two things: a product feed and a tracked deep link per product. The jeweller's feed is a gzipped CSV of 14,274 rows that Awin refreshes every four hours. A fetch script downloads, decompresses and parses it; a price filter from 2 to 150 EUR keeps 6,111 rows; a curation script applies category and brand exclusions, de-duplicates variants on the model number, since the same design comes in gold, silver and several sizes, and scores what is left. The first cut was 100 products, then 200 split evenly between women and men, and the catalogue stands at 298 across the programmes today.
The feed carries a name, a price, a brand, a hierarchical category and up to five images, and nothing about colour, material or occasion. The pipeline fills the gap. Each product is inserted with its deep link, its image with the background removed and its bounding box measured so it can sit in a flatlay next to the user's own garments, tags from gpt-4o-mini for colour, style, pattern, material, season and occasion, a gender derived from the merchant category, and a 512-dimensional CLIP vector stored in a pgvector column. That last step matters most: the user's garments carry the same embedding, so visual similarity between a product and a wardrobe is one cosine distance.
- 1.Programme joined; feed and deep links unlocked→
- 2.fetch-awin-feed: gzip CSV, 14,274 rows→
- 3.Price filter 2 to 150 EUR: 6,111→
- 4.filter-feed: exclusions, dedup on model number, quality score→
- 5.Ingest: background removal, bounding box, gpt-4o-mini tags, gender→
- 6.CLIP vector, 512-d, pgvector→
- 7.get_marketplace_feed scores and ranks for the user→
- 8.Tap: deep link out; purchase webhook posts to Slack
An engine with no cold start
Most recommenders have a phase one for new users and a phase two for known ones, with a threshold between them. This one has neither. Every user carries a richness score between 0 and about 1 that says how much the system knows: a weighted sum of saturating functions of how many garments, vectors, outfits, interactions and feedback events they have, plus a few profile flags. A new account scores near zero and sees a discovery feed built from global popularity, product quality, recency and click-through with a little exploration noise. A power user scores high and sees a personal feed built from CLIP similarity to their own garments, their past interactions, the categories missing from their wardrobe, their style, colours and price range. Everyone in between sees a blend, and the blend moves as they use the app.
The marketplace has three tabs. For You is the standard blend. Missing in Wardrobe raises the effective richness to at least 0.5 and puts 60 percent of the personal score on wardrobe gaps, so it answers one question: what do you not own. Discover forces richness to zero and shows the same feed to everyone. One SQL function computes all of it in seven steps, from the user's dismissals and saves through CLIP scores and the context row to a diversified page that caps any brand at three products and any category at five, and returns each product with a reason code: a CLIP match, a wardrobe gap, trending, new, exploration, a style match or popular.
Three rules keep it honest. Penalties are soft, never exclusions: the opposite gender costs 0.6, a product dismissed in the last thirty days 0.9, one already saved 0.1. Every impression, view, click, save and dismissal is kept raw for training and rolled up by triggers into per-product and per-user statistics, with five cron jobs computing click-through, rolling windows, engagement scores and daily aggregates and archiving events older than ninety days. And the user's context row is recomputed by triggers whenever a garment, an outfit, an interaction, a rejection or a profile field changes, so the feed never scores against stale data.
Review of
Formulas
- r
- is the user's richness: 0.25 closet + 0.20 vectors + 0.20 interactions + 0.15 outfits + 0.10 behaviour + 0.10 profile, each a saturating 1 − 1 / (1 + n / k)
- discovery
- is 0.35 popularity + 0.25 quality + 0.20 recency + 0.10 click-through + 0.10 exploration noise
- personal
- is 0.30 CLIP similarity + 0.25 interactions + 0.15 wardrobe gap + 0.10 style + 0.10 taste + 0.05 colour + 0.05 price
Missing in Wardrobe uses max(r, 0.5) and moves the gap weight to 0.60; Discover sets r to 0. The half-way points k are 10 garments, 8 vectors, 20 interactions, 8 outfits and 15 feedback events.
The loop, per user
- 1Context: garments, vectors, outfits, interactions and profile feed one richness score
- 2Score: one SQL function blends discovery and personal signals by that score
- 3Diversify: brand cap three, category cap five, a reason code per product
- 4Show: For You, Missing in Wardrobe or Discover
- 5Log: every impression, view, click, save and dismissal, raw
- 6Roll up: triggers and cron jobs update product and user statistics
- 7Recompute: any change to the wardrobe or the profile rewrites the context row
What the numbers say
The engine is built and the catalogue is live, and the funnel it feeds is waiting on distribution. On the production pull of 15 September 2026, 45 of 145 accounts had consented to affiliate tracking, 15 accounts had engagement rows, and the interaction log held no affiliate clicks and no purchases. The app is still on TestFlight, so the marketplace has been seen by beta users and by nobody else. The honest reading is that the merchant terms are real, the catalogue is real, and the conversion rate is not yet WRDB's to claim.
That is also why it was built this way. The richness score means the first thousand users get a sensible feed on day one without a training set, the raw log means the first real clicks are already training data, and the purchase webhook means the first sale will land in Slack before anyone looks at a dashboard.