Skip to main content
The iFood dataset creates a multi-schema decisioning environment modeled after a food delivery platform’s multi-wave direct marketing campaign. It is the most architecturally complex dataset pack, featuring 3 data tables that join on customer_id, 6 campaign offers, 4 delivery channels, custom outcome types, and a cross-schema segment. Based on the Kaggle iFood Marketing Campaigns dataset (CC0: Public Domain).
Unlike the single-table Starbucks dataset, iFood is a multi-schema pack: 3 tables that join on customer_id. It demonstrates cross-table predictor joins, 6 custom outcome types (one per campaign wave), Epsilon-Greedy with 6 arms, and cross-schema segment definitions.

What Gets Created

Entity TypeCountDetails
Schemas3ifood_customers, ifood_spending, ifood_campaigns
Categories5Campaign 1 through Campaign 5 & Response
Channels4Web, Catalog, Store, Deals
Offers6Campaign 1-5 Offers + Current Response Offer
Creatives246 offers x 4 channels
Qualification Rules0None (open targeting)
Outcome Types6accepted_cmp1 through accepted_cmp5 + response
Algorithm Models2Scorecard + Epsilon-Greedy
Experiments1Scorecard (70%) vs Epsilon-Greedy (30%)
Segments1High-Value Spenders (cross-schema join)
Customer Rows500IFOOD-000000 through IFOOD-000499

Step-by-Step Walkthrough

1
Load the iFood Dataset
2
curl -X POST "http://localhost:3000/api/v1/seed-dataset/ifood?force=true" \
  -H "Content-Type: application/json" \
  -H "X-Requested-With: XMLHttpRequest"
3

Expected Response (201 Created)

{
  "message": "iFood Campaigns loaded successfully",
  "counts": {
    "schemas": 3,
    "categories": 5,
    "subCategories": 6,
    "channels": 4,
    "offers": 6,
    "creatives": 24,
    "qualificationRules": 0,
    "contactPolicies": 0,
    "outcomeTypes": 6,
    "models": 2,
    "experiments": 1,
    "decisionFlows": 1,
    "segments": 1,
    "ifood_customers_rows": 500,
    "ifood_spending_rows": 500,
    "ifood_campaigns_rows": 500,
    "interactions": 500,
    "interactionSummaries": 500
  },
  "datasetKey": "ifood"
}
4
Explore the Multi-Schema Architecture
5
The 3-table architecture is the defining feature of iFood:
6
curl "http://localhost:3000/api/v1/schemas" \
  -H "X-Requested-With: XMLHttpRequest"
7
ifood_customers        ifood_spending          ifood_campaigns
───────────────        ──────────────          ───────────────
customer_id (PK) ────> customer_id (PK) ────> customer_id (PK)
income                 wines                   accepted_cmp1
education              fruits                  accepted_cmp2
marital_status         meat                    accepted_cmp3
age                    fish                    accepted_cmp4
kidhome                sweets                  accepted_cmp5
teenhome               gold                    response
dt_customer            total_spend             complain
recency_days                                   deals_purchases
                                               web_purchases
                                               catalog_purchases
                                               store_purchases
                                               web_visits
8
Get a Recommendation with Cross-Schema Attributes
9
Pass attributes from all three schemas for cross-schema scoring:
10
curl -X POST "http://localhost:3000/api/v1/recommend" \
  -H "Content-Type: application/json" \
  -H "X-Requested-With: XMLHttpRequest" \
  -d '{
    "customerId": "IFOOD-000042",
    "channel": "web",
    "limit": 3,
    "context": {
      "placement": "homepage_banner",
      "sessionType": "returning"
    },
    "customerAttributes": {
      "income": 72000,
      "education": "PhD",
      "marital_status": "Married",
      "age": 45,
      "kidhome": 1,
      "teenhome": 0,
      "recency_days": 12,
      "total_spend": 1850.50,
      "wines": 800.00,
      "meat": 650.00,
      "web_purchases": 8,
      "catalog_purchases": 3,
      "store_purchases": 5,
      "deals_purchases": 4,
      "web_visits": 12,
      "accepted_cmp1": 0,
      "accepted_cmp2": 1,
      "accepted_cmp3": 0,
      "accepted_cmp4": 0,
      "accepted_cmp5": 1,
      "response": 0
    }
  }'
11

Expected Response

{
  "customerId": "IFOOD-000042",
  "recommendations": [
    {
      "offerId": "...",
      "offerName": "iFood: Campaign 1 Offer",
      "score": 0.87,
      "rank": 1,
      "reason": "High income + high spend + recent activity"
    },
    {
      "offerId": "...",
      "offerName": "iFood: Campaign 2 Offer",
      "score": 0.82,
      "rank": 2,
      "reason": "Previous campaign 2 acceptance"
    },
    {
      "offerId": "...",
      "offerName": "iFood: Current Response Offer",
      "score": 0.74,
      "rank": 3,
      "reason": "Active response target"
    }
  ],
  "modelUsed": "ifood-scorecard",
  "experimentArm": "champion"
}
12
Record a Campaign-Specific Outcome
13
Use the custom outcome types to track per-campaign acceptance:
14
curl -X POST "http://localhost:3000/api/v1/respond" \
  -H "Content-Type: application/json" \
  -H "X-Requested-With: XMLHttpRequest" \
  -d '{
    "customerId": "IFOOD-000042",
    "offerId": "<campaign-3-offer-id>",
    "creativeId": "<cmp3-web-creative-id>",
    "channelId": "<web-channel-id>",
    "outcomeTypeKey": "accepted_cmp3",
    "interactionType": "conversion",
    "direction": "inbound",
    "context": {
      "source": "web_checkout",
      "campaignWave": 3
    },
    "outcome": {
      "key": "accepted_cmp3",
      "classification": "positive",
      "value": 45.00
    }
  }'
15
Preview the Cross-Schema Segment
16
The High-Value Spenders segment joins ifood_customers (income > 60k)withifoodspending(totalspend>60k) with `ifood_spending` (total_spend > 1000):
17
curl "http://localhost:3000/api/v1/segments/<segmentId>/preview?limit=5" \
  -H "X-Requested-With: XMLHttpRequest"
18
Run a Batch Campaign via Segment
19
curl -X POST "http://localhost:3000/api/v1/recommend/batch" \
  -H "Content-Type: application/json" \
  -H "X-Requested-With: XMLHttpRequest" \
  -d '{
    "segmentId": "<high-value-spenders-segment-id>",
    "channel": "catalog",
    "limit": 1,
    "context": { "campaignRun": "ifood-march-batch" }
  }'
20
Train the Epsilon-Greedy Model
21
curl -X POST "http://localhost:3000/api/v1/algorithm-models/<epsilon-model-id>/train" \
  -H "Content-Type: application/json" \
  -H "X-Requested-With: XMLHttpRequest"
22
Check Experiment Results
23
curl "http://localhost:3000/api/v1/experiments/<experimentId>/results" \
  -H "X-Requested-With: XMLHttpRequest"

Offer Priority Strategy

OfferPriorityStrategy
Campaign 1 Offer90Broad acquisition — highest priority for new customers
Campaign 2 Offer80Refined retargeting based on Campaign 1 learnings
Campaign 3 Offer70Mid-tier customer focus with category promotions
Campaign 4 Offer65Seasonal promo with personalized bundles
Campaign 5 Offer55Re-engagement for lapsed customers
Current Response50Active response — primary Epsilon-Greedy optimization target

Custom Outcome Types

iFood defines 6 custom outcome types, one per campaign wave:
Outcome KeyNameClassification
accepted_cmp1Campaign 1 Acceptedpositive
accepted_cmp2Campaign 2 Acceptedpositive
accepted_cmp3Campaign 3 Acceptedpositive
accepted_cmp4Campaign 4 Acceptedpositive
accepted_cmp5Campaign 5 Acceptedpositive
responseCurrent Responsepositive
Each outcome type maps 1:1 to a campaign acceptance flag in the ifood_campaigns table. This allows the Epsilon-Greedy model to track which arm (campaign) has the highest conversion rate.

Epsilon-Greedy Model

The iFood Epsilon-Greedy is a 6-armed bandit — one arm per campaign offer:
ParameterValueDescription
Arms6One per campaign (Cmp1-5 + Response)
Epsilon0.1515% exploration rate (initial)
Decay0.99Epsilon decays by 1% per training cycle
Arm Rewards (after 500 interactions):
Arm 0: Campaign 1   pulls: 95  reward: 0.18
Arm 1: Campaign 2   pulls: 82  reward: 0.14
Arm 2: Campaign 3   pulls: 110 reward: 0.22  ← BEST
Arm 3: Campaign 4   pulls: 78  reward: 0.12
Arm 4: Campaign 5   pulls: 85  reward: 0.15
Arm 5: Response      pulls: 50  reward: 0.16

Experiment: Scorecard vs Epsilon-Greedy

ArmModelTraffic %Strategy
ChampioniFood: Scorecard Model70%Rule-based scoring (income ≥ 60k,totalspend60k, total_spend ≥ 1000, recency ≤ 30 days)
ChallengeriFood: Epsilon-Greedy Model30%6-arm bandit with epsilon=0.15, decay=0.99
Auto-promotion is disabled (autoPromote: false). You must manually promote the winner after reviewing results. Wait until the p-value drops below 0.05 and the uplift exceeds 2% before promoting.

What to Look For

  • Multi-schema predictors: The Scorecard model uses predictors from all 3 schemas: income from customers, total_spend from spending, and recency_days from customers.
  • Cross-schema segment: The High-Value Spenders segment joins two tables via customer_id, finding customers with income > 60kANDtotalspend>60k AND total_spend > 1000.
  • 6 custom outcome types: Per-campaign tracking enables the Epsilon-Greedy model to learn which campaign wave performs best.
  • 4 delivery channels: Web (banner), Catalog (print), Store (signage), Deals (webhook) — each with different delivery modes.
  • Batch + Segment: The batch endpoint iterates over all customers in the segment, runs the decision pipeline for each, and returns ranked offers for offline campaign targeting.