Org Web Adapter

hungryroot/2026-hackathon/customer-aquisition.org

Customer Segmentation Dimensions Beyond Diet & Tenure

#+DATE: 2026-07-15

Context

Explored the codebase to map what customer attributes already exist beyond

"diet type" and "how long they've been a customer." Findings from three

parallel searches (customer profile models, order/purchase behavior, and

segmentation/analytics infra).

Household & life context

- ~Quiz~ / ~OccasionSurvey~ (=app/models/quiz.py=, =app/models/occasion_survey.py=)

- household size, num adults / young children / older children

- weekly grocery spend tier

- per-meal frequency (breakfast/lunch/dinner/snacks)

- sweets/fruit desire

- ~CustomerInfo.num_people~, ~try_new_items~ (adventurousness), ~spicy_level~

- ~Customer.occasion_goals~ M2M -> ~OccasionGoal~ (e.g. "eat more plants," "save time," "lose weight")

- ~Customer.grocery_ideals~ M2M -> ~GroceryShoppingIdeal~

Taste & product affinity

- ~CustomerTag~ (=app/models/customer_tag.py=): per-tag like/dislike score, explicit vs inferred

- ~DishPreference~, ~Periodicity~ (per-product NEVER/SOMETIMES/OFTEN), ~FirstBoxPreference~, ~CustomerOccasionEntityPreferences~

- Rating/feedback trail: ~ProductRating~, ~PairingRating~, ~BundleRating~, ~CustomerFoodFeedback~, ~ProductRatingFeedback~ (quality/packaging/never-want flags)

Purchasing behavior (richest untapped segmentation signal)

- Cadence & disruption: ~Order.frequency~, ~Order.status~ history (SKIPPED, HELD, RECURRING...), ~CustomerLog~/~OrderLog~ actions ~SKIP_ORDER~, ~HOLD_BUNDLE~, ~CHANGE_FREQUENCY~

- Customization intensity: ~Order.is_customized~, ~is_personalized~, ~is_swapfilled~, ~has_customized_pairings~; ~OrderFinancials.shuffle_credit_delta~ / ~customize_credit_delta~ -- quantifies how much a customer deviates from the auto-filled box

- Spend: ~Order.subtotal/total/discount~, ~OrderFinancials~ (plan price, shuffle adjustment, add-on subtotal), ~OrderDetail.occasion~ (category mix: dinner/lunch/breakfast/snack)

- Order sequence/tenure-adjacent but more granular: ~Order.sequence~, ~nth_shipped~ (delivered-only count)

Lifecycle & risk

- ~Customer.status~, ~cancel_date~, ~cancel_reason~ + structured ~CancelReason~/~CancelSubreason~ (with ~is_first_box~ flag -- distinguishes early churners)

- ~Customer.cc_failures~ (payment friction), ~is_vip~, ~no_auto_credit~

- ~OrderLog~ action ~HELP_SUBMITTED~ (self-service complaint usage)

Acquisition & channel

- ~CustomerInfo~ UTM fields (x2: signup + checkout), ~discovery_survey~ / ~AttributionSurveyAnswer~ ("how'd you hear about us"), ~Customer.facebook_id/google_id/apple_id~, ~Referral~, ~Customer.referral_code~

- Device/platform: ~CustomerInfo.ua_*~ fields, ~client_name~

Value & loyalty

- ~PromoCode~/~OrderPromoCode~: discount type, channel, winback flags -- reveals price sensitivity and reactivation history

- ~CustomerRewardCredits.lifetime_earned_credits~, ~CustomerRewardsLedger~, ~EarnedIncentive~ -- closest thing to a loyalty-depth signal

Experimentation as segmentation

- ~CustomerExperiment~ (customer x experiment x variant) -- not built for segmentation but usable as a targeting/cohort mechanism today (see ~bulk_enroll_experiments~ management command's ~--include_filters~/~--exclude_filters~ for arbitrary Q() targeting)

External sync

- Braze (=braze/attrsync.py=) already receives ~60 computed attributes per customer (tag booleans, goals, plan info, ~num_delivered~, ~random_user_segment~ bucket) -- effectively the existing "segmentation API" surfaced to marketing today

- Segment.com receives behavioral events (cart, search, order, rating) but no computed segment field

Notable gap

No dedicated RFM, LTV, engagement score, or churn-prediction model/field exists --

these would need to be computed from the raw signals above (order spend/frequency

history, customization behavior, cc_failures, cancel patterns).

Possible hackathon angle: a computed ~CustomerEngagementScore~ or scheduled job

populating Braze/Segment with recency-frequency-monetary buckets.