Read this first
Events do not update batch data. When a player places a bet and an event fires, their daily batch profile is unchanged — it only moves in the next nightly sync. A scheduled campaign sees yesterday's snapshot, never what happened five minutes ago.
Start here Two separate channels
Optimove receives player information in two totally different ways. They do not mix. Every block in this document is colour-coded to whichever channel it belongs to.
- Batch · scheduled
- Events · triggered
- Campaign output
- Reference
Batch data
Daily snapshotEvery night, Optimove pulls a fresh copy of every player's profile: balance, level, game history, transaction history. A daily "state of every player."
- Updates once per day.
- Covers all players, including those not active today.
- Used to build target groups and send scheduled campaigns.
- Source: our database.
Events
Real-time signalsWhen a player does something right now — places a bet, deposits, levels up — a signal fires instantly to Optimove. These are moments, not profiles.
- Fires the instant something happens.
- Fires on a player or system action. Most are in-session; some, such as redemption completed, fire from backend processes.
- Used to trigger real-time campaigns.
- Does not update batch or daily data.
Channel 1 Batch data — the daily snapshot
Every night, Optimove pulls a fresh copy of the entire player database. Here is how that works.
-
Data lives in our database
Player profiles, balances, levels, game activity, and transaction history.
-
Nightly sync to Optimove
Optimove automatically pulls this data once per day into its own system.
-
Optimove builds profiles
Each player gets a profile inside Optimove with all their attributes up to date.
-
Marketers create target groups
Filter players by any attribute: "level 5+, deposited $50+ in past 30 days."
-
Scheduled campaign sent
Campaign fires at a set time — 5am, say — to everyone in the target group.
Batch data is a snapshot. It shows where every player stood at the end of yesterday. It is not live.
What Optimove receives — four data sets
Batch data is not a single file. It is four separate views, each with a different purpose. Optimove reads all four nightly and cross-references them by player ID.
Customer profiles
View 1 · one row per playerUpdated nightly · the primary segmentation dataset
- SC balance
- GC balance
- Level + rank
- Tags
- Is blocked
- Allow email / SMS
- Country + state
- Last login date
- Registration date
- Acquisition source
- Email + phone
- Name + username
Game activity
View 2 · player × game × dayHow Optimove uses these rows is defined on Optimove's side
- SC bet amount
- SC win amount
- GC bet + win amount
- Bet + win counts
- Net gaming revenue
Raw daily rows, one per player/game/day. Optimove aggregates these into lifetime, 3-month, and 2-week totals for bet amounts, win amounts, NGR, game counts, win ratios, and more.
Transactions
View 3 · one row per transaction- PURCHASE — coin pack bought, amount + status
- REDEEM — cashout request, amount + status (pending / approved / rejected)
- BONUS_SC / BONUS_GC — bonus coins awarded
Individual transaction records. Optimove aggregates these into lifetime, 3-month, and 2-week totals for purchase amounts, redemption amounts, counts, cashout ratios, and more.
Game catalog
View 4 · one row per gameUsed by Optimove to label game activity with names and categories
- Game ID + name
- Game category
All attributes available in Optimove today
Everything below is already live. Sourced from the four batch views — raw fields passed through directly, or computed by Optimove from the raw data.
Attribute index
Reference- Player ID
- First Name
- Last Name
- Alias
- Mobile Number
- Date of Birth
- Age
- Gender
- Country
- State
- City
- Address
- Language
- Currency
- Registration Date
- Last Login Date
- Last Active At
- Tags
- Is Blocked
- Is Test
- Is Optin
- Is Email Verified
- Is SMS Verified
- Is Top Spender?
- Platform Preference
- Platform Preference, Last 3 Months
- Reachable for Web Push
- Casino Name
- Referral Type
- Referred By Id
- Marketing Id
- Affiliate Id
- Promo Code
- Registered Platform
- UTM Source (Last Session)
- UTM Medium (Last Session)
- UTM Campaign (Last Session)
- UTM Content (Last Session)
- UTM Term (Last Session)
- Allow Email
- Allow SMS
- Allow Push
- Allow Whatsapp
- Email Valid, Lifetime
- OptiMail Unsubscribed
- OptiMail — Days Since Last Opened
- OptiMail — Days Since Last Clicked
- Most Effective Channel
- Balance (SC)
- Gc Balance
- Total Pending Redeems
- Total Balance Loss
- Total SC Casino Bet Amount, Lifetime
- Total SC Casino Bet Amount, Last 3 Months
- Total SC Casino Bet Amount, Last 2 Weeks
- Total SC Casino Win Amount, Lifetime
- Total SC Casino Win Amount, Last 3 Months
- Total SC Casino Win Amount, Last 2 Weeks
- Total GC Casino Bet Amount, Lifetime
- Total GC Casino Bet Amount, Last 3 Months
- Total GC Casino Bet Amount, Last 2 Weeks
- Total GC Casino Win Amount, Lifetime
- Total Casino NGR, Lifetime
- Total Casino NGR, Last 3 Months
- Total Casino NGR, Last 2 Weeks
- Average SC Casino Bet Amount, Lifetime
- SC Win Ratio, Lifetime
- SC Win Ratio, Last 3 Months
- GC to SC Ratio, Lifetime
- GC to SC Ratio, Last 3 Months
- Number of Bets Made
- Number of SC Casino Games, Lifetime
- Number of GC Casino Games, Lifetime
- Number of Casino Winning Games, Lifetime
- Number of Casino Game Days, Lifetime
- Number of Casino Game Days, Last 3 Months
- Number of Casino Game Days, Last 2 Weeks
- Number of Casino Mobile Games, Lifetime
- Number of Casino Web Games, Lifetime
- Favorite Casino Game
- Favorite Category
- Gameplay Activity on Slots
- Gameplay Activity on Originals
- Gameplay Activity on Other Games
- First Casino Game Date
- Last Casino Game Date
- Last Bet Made
- Days Since Last Casino Game
- Days Since Last SC Casino Game
- SC Bet Percentile By LCS
- SC Bet Percentile By LCS, Last 3 Months
- SC Bet Percentile By LCS, Last 2 Weeks
- Total Purchase Amount, Lifetime
- Total Purchase Amount, Last 3 Months
- Total Purchase Amount, Last 2 Weeks
- Number of Purchases, Lifetime
- Number of Purchases, Last 3 Months
- Number of Purchases, Last 2 Weeks
- Number of Purchase Days, Lifetime
- Number of Purchase Days, Last 3 Months
- Number of Purchase Days, Last 2 Weeks
- Number of Purchase Days, Last Calendar Month
- Average Purchase Amount, Lifetime
- Average Purchase Amount, Last Month
- Average Purchase Amount, Last 3 Months
- Average Monthly Purchase Amount, Lifetime
- First Purchase Date
- First Purchase Amount, Lifetime
- Last Purchase Amount, Lifetime
- Days Since First Purchase
- Days Since Last Purchase
- Purchase Amount Monthly Change, Lifetime
- Purchase Amount Since Reactivated
- Purchases Since Reactivated
- Purchase Percentile By LCS
- Purchase Percentile By LCS, Last 3 Months
- Frequency, Last 3 Months
- Frequency, One Year
- Total Redeem Amount, Lifetime
- Total Redeem Amount, Last 3 Months
- Total Redeem Amount, Last 2 Weeks
- Number of Redeems, Lifetime
- Number of Redeem Days, Lifetime
- Last Redeem Date
- Last Completed Redemption Date
- Days Since Last Redeem
- Cashout Ratio, Lifetime
- Cashout Ratio, Last Month
- Cashout Ratio, Last 3 Months
- Net Cash, Lifetime
- Net Cash, Last 2 Weeks
- Net Purchase (lifetime)
- Net Purchase Last 3 Months
- Net Purchase including pending and balance
- Net Score
- NGR Total Purchase − Total Redemption
- Redemption Ratio
- Lifecycle Stage
- Previous Lifecycle Stage
- Lifecycle Stage Before Churn
- Days Since Lifecycle Stage Change
- Activity Days, Lifetime
- Number of Activity Days, Lifetime
- Number of Activity Days, Last 3 Months
- Number of Activity Days, Last 2 Weeks
- Days Since First Activity
- Days Since Last Activity
- Days Since Last Login
- Days Since Last Visit
- Days Since Registration
- Months Since Registration
- Last Activity Date
- Dormant Activity Layer
- Dormant Type
- Number of Times Churned, Lifetime
- Days In Churn, Lifetime
- Days In Reactivated, Lifetime
- Days Since Last Reactivation
- Number of Visits, Last 14 Days
- Number of Visits, Last 30 Days
- Avg. Session Time in Minutes
- Total Visit Time, Last 14 Days
- Total Visit Time, Last 30 Days
- Churn Probability Score
- Churn Factor
- Churn Factor, One Year
- Reactivation Probability Score
- Conversion Probability Score
- Becoming Top Spender Score
- Rank in Churn Probability
- Rank in Reactivation Probability
- Rank in Conversion Probability
- Rank in Becoming Top Spender
- Rank by LCS Churn Probability
- Rank by LCS Becoming Top Spender
- Response Rate, Last 7 Days
- Response Rate, Last 30 Days
- Number of Campaigns, Last 7 Days
- Number of Campaigns, Last 30 Days
- Most Effective Channel
- Content — Game Category
- Content — Promotion Type
- Content — Tone of Voice
- Random Customer Percentage
- Random Customer Slice
Channel 2 Events — real-time signals
When a player does something, a signal fires instantly. These drive campaigns for players who are active right now.
-
Player action
Player places a bet, deposits, levels up.
-
Event fires
Signal sent instantly with rich data attached.
-
Queue
Brief buffer, milliseconds, to guarantee delivery.
-
Optimove receives
Event arrives in Optimove within seconds.
-
Campaign triggers
If conditions match, the campaign fires immediately.
Events we send — with what is attached
Each event carries a snapshot of that player's current state, so real-time campaigns have fresh data without needing to query the database. Full payloads are in the event catalogue.
bet_finished
After every betFires whether the player won or lost. Carries current balances, level, risk score, game result, and DWH aggregate metrics — all fresh at the moment of the bet.
sc_balance: 12232.79 risk_total_risk_score: 0
level_name: "Unicorn 3" login_count_7d: 3
bet_amount_today: 13750.20 bet_amount_7d: 73290.62
bet_amount_lifetime: 85998.23 win_amount_today: 10909.28
purchase_count_lifetime: 3 bonus_claimed_30d: 11.02
completed_redemption_* fields are excluded to stay within
Optimove's attribute count limit.
deposit
On every purchase
Carries updated balances, level, risk score, purchase amount,
sw_package_type, is_first_time_deposit, affiliate and
marketing IDs, and DWH aggregate metrics.
sc_balance: 12232.79 deposit_in_usd: 2.99
sw_package_type: "standard" is_first_time_deposit: false
affiliate_id: "N/A" purchase_amount_today: 0
purchase_amount_lifetime: 2.97 purchase_count_lifetime: 3
completed_redemption_* fields are excluded to stay within
Optimove's attribute count limit.
level_change
Fires on level up
Carries new level, rank, and current balances. A good trigger for congratulations.
redemption_requested
Cashout submitted
Carries redemption amount and current pending redemption total.
redemption_completed
Cashout approved
Carries updated redemption history windows. Triggers for completed redeemers.
bonus_claim
Bonus claimed
Carries cumulative bonus totals. Enables campaigns for frequent bonus claimers.
sign_up
Once, on registration
Triggers onboarding campaigns. Carries initial profile state.
user_active
Every ~120s while in session
Full snapshot of all DWH aggregate metrics, plus
completed_redemption_* unlike bet_finished and deposit. Keeps the RT
Attributes V2 profile fresh even in sessions with no bets or deposits.
An event firing does not update a player's batch profile. The batch profile updates once per night via the daily sync, period. A campaign scheduled for tomorrow will use tomorrow night's batch data, not the events that fired today.
Phase 2 enrichment — DWH aggregates on all events
All backend events now carry the fields below.
- bet_amount_today/7d/30d/lifetime
- win_amount_today/7d/30d/lifetime
- purchase_amount_today/7d/30d/lifetime
- purchase_count_today/7d/30d/lifetime
- completed_redemption_amount_7d/30d/lifetime
- completed_redemption_count_30d/lifetime
- bonus_claimed_30d/lifetime
- login_count_7d
- redemption_rate_lifetime
- net_purchase_lifetime
All DWH aggregate values lag roughly 30 seconds behind real values. A
bet_finished event can fire with bet_amount_today = 0 even
though the bet amount is non-zero — the DWH has not yet reflected it.
Removed from bet_finished and deposit to stay within
Optimove's per-event attribute count limit. These fields are present on
redemption_requested, redemption_completed,
level_change, bonus_claim, user_active, and
initial_daily_balance.
bonus_claimed can be negative — it is calculated as SUM(bonus_amount −
bonus_give_up). Free spin wins are counted in win amounts instead. All numeric DWH
fields default to 0, never null. All string fields
(affiliate_id, sw_package_id) default to
"N/A"
when empty.
Event configuration Three event types in Optimove
Before creating a campaign, events must be configured in Optimove's back office as one of three types. Each event is one type only, not all three.
Simple event
ConfiguredOne action → fires immediately, every time
Fires once each time the defined action happens. The campaign evaluates trigger conditions against each event independently and fires if all pass. This is the most common type.
Swivel examples- deposit → show $20 offer if player bought a $10 standard pack
-
bet_finished → top-up offer if
sc_balance < 1 - bonus_claim → engagement follow-up campaign
-
redemption_requested → purchase incentive if
sc_balance < 2
All Swivel events are Simple events by default.
Repeated event
ConfiguredEvent fires always · trigger activates on the Nth occurrence
The event fires every time the action happens — always. The trigger activates when the count reaches N. Optimove tracks occurrences internally; no counter value is sent from Swivel. Two counting modes:
- Occurred X times — fires on the Xth event. The counter starts when the customer enters the trigger logic, not from account creation.
- Consecutive X times — the same event must fire back to back. Any different event resets the streak. Whether a condition mismatch on the same event type also resets is unverified.
To require N occurrences within a timeframe (3 deposits within 3h), add the same event multiple times in the trigger sequence and set the timeframe at the bottom of the trigger config. Do not use a single "Occurred N times" condition for this — it has no time window.
- 3rd deposit after trigger entry → loyalty reward (Occurred 3 times)
- 3 deposits within 3h → loyalty reward (Deposit ×3 in trigger, 3h window at bottom)
- 3 consecutive bets → "you're on a roll" bonus (any non-bet event resets)
deposit and bet_finished are set up as Repeated
events. Occurrence count is tracked by Optimove from trigger entry.
Uncompleted sequence
Needs setupA happens, B expected but does not → fires
Optimove watches for a first action (A), then waits for a follow-up action (B). If B does not happen within the time window, the campaign fires. This is the cart-abandonment equivalent — the player started a journey but did not finish it.
Swivel examples- sign_up → no deposit within 30 min → first purchase welcome offer
- deposit → no bet_finished within 15 min → "you have coins, try a game"
- bet_finished → no new bet within 20 min → keep-playing nudge
Each sequence (A → expected B) must be added as a new event in Optimove BO before it can be used in any campaign.
Campaigns Two types of campaign
The type of campaign depends on which channel it listens to — batch data or events.
Scheduled campaign
Batch dataFor inactive players
-
Batch data refreshed last night
Every profile is up to date as of yesterday's snapshot.
-
Target group filters applied
"Not active in 7+ days AND country = US AND is_blocked = No AND total purchases over $100."
-
Campaign fires at scheduled time
5am ET, say — when servers are quiet and the message reads as a morning nudge.
-
Email or push sent
"We miss you — here's 500 GC to come back."
Win-back, reactivation, loyalty milestones, risk-based segmentation.
Triggered campaign
EventsPrimarily active players — though some events fire regardless of session
-
Player does something right now
Places a bet, deposits, levels up, completes a redemption.
-
Event fires instantly
Signal arrives at Optimove within seconds, carrying fresh player data.
-
Conditions checked in real time
"Deposit event AND first purchase ever AND balance now over 1000 SC."
-
Campaign triggers immediately
Pop-up, push notification, or bonus fires while the player is still in session.
Purchase upsell, level-up celebration, first-deposit welcome, redemption follow-up.
Target groups — used in both campaign types
A target group is a saved filter of player attributes. Both scheduled and triggered campaigns require a target group — it defines the eligible pool. Use common sense about what belongs there. Balance changes every session, so a batch snapshot will always be stale. Average purchase amount means nothing for a player with two purchases.
In scheduled campaigns
The TG defines who gets the email or push at the scheduled time.
In triggered campaigns
The TG defines who is eligible before the trigger condition is checked.
Target group membership is evaluated by Optimove at a time you do not control, against the nightly batch snapshot. That single fact decides what may and may not go into a target group.
Critical distinction Target groups vs trigger conditions
Two completely different places where Optimove checks whether a player should receive a campaign. They must carry different types of data.
Target group
Batch · unknown time · slow fieldsUse stable, slowly-changing attributes. Balance changes every session, so a batch snapshot is always behind. Averages and ratios are only meaningful if the player has enough data points to make them statistically valid.
Put here- Country = US
- Is banned = No
- Opted in = Yes
- Player type: new vs existing
- Total purchases > $50 — lifetime total, stable
- Redemption count > 5 — stable count
-
sc_balance < 1— changes every bet, always stale - Average purchase amount under 5 purchases — meaningless
Balance belongs in the trigger condition, not here. It changes on every bet, and the batch snapshot will never reflect the right moment. Lifetime totals and counts are fine — they accumulate slowly.
Trigger condition
Checked instantly · live dataThe trigger condition is evaluated the instant an event arrives, against the data attached to that event. The event payload carries live values from the exact moment of the action.
Put here-
sc_balance < 1 -
risk_score < 70 -
purchase_amount = $10 -
avg_purchasebetween $4.99 and $9.99 -
pending_redemption < 2 SC
Why this works: the event payload is built at the exact moment the player acts. Balance, risk score, purchase amount — all reflect reality right now. Trigger conditions read that snapshot instantly.
Worked example — bet finished, balance under 1 SC
-
Target group, static
Existing / new (visitor) user · not banned · opted in · country = US
-
Event fires
bet_finished { sc_balance: 0.8, risk_score: 45 } -
Trigger condition
risk_score < 70passes ·sc_balance < 1passes -
Campaign fires
Top-up offer shown to the player.
Step by step How to build a campaign in 4 steps
Every campaign — triggered or scheduled — follows the same setup flow.
-
Define your target group — who is eligible?
The target group is the pool of players who could receive this campaign. For triggered campaigns, use slow-changing attributes only. Never put balance, purchase amounts, or redemption data here — those values are stale by the time Optimove reads them.
Recommended base TG
Add to nearly every triggered campaign- Country = US
- Is Blocked = No
- Allow Push / Email = Yes
- Player Type = Existing
Do not add
sc_balanceor purchase amounts to a target group for triggered campaigns. Optimove evaluates TG membership at an unknown time using batch data — those values will be outdated by the time the event fires. -
Choose your trigger — what starts the campaign?
Pick an event from Swivel. The event type (Simple, Repeated, Uncompleted Sequence) is already determined by how the event was configured in Optimove BO — you do not choose it here. You can also configure a trigger as a combination of events within a time window: sign_up followed by deposit within 30 min, or 3 bet_finished events within 1 hour.
- bet_finished
- deposit
- redemption_requested
- redemption_completed
- bonus_claim
- level_change
- sign_up
- user_active
- initial_daily_balance
- cashier_exit
- promo_award_selected
-
Set trigger conditions — what must be true in the payload?
Conditions are checked the instant the event fires, against the live data attached to that event. All conditions must be true for the campaign to fire.
Core fields — live snapshot, Phase 1, all events- sc_balance
- gc_balance
- risk_total_risk_score
- xp_total
- xp_to_next_level
- pending_redemption_amount_in_usd
- level_name
- level_rank
- deposit_in_usd
- is_first_time_deposit
- sw_package_type
- affiliate_id
- marketing_id
- payment_method
- is_winning_bet
- amount_won_in_usd
- original_amount
- multiplier
- game_id
- game_type
- bet_amount_today/7d/30d/lifetime
- win_amount_today/7d/30d/lifetime
- purchase_amount_today/7d/30d/lifetime
- purchase_count_today/7d/30d/lifetime
- bonus_claimed_30d/lifetime
- login_count_7d
- redemption_rate_lifetime
- net_purchase_lifetime
- completed_redemption_amount_7d/30d/lifetime
- completed_redemption_count_30d/lifetime
DWH aggregate fields lag ~30 secondsA player places their first ever bet of 30 SC.
bet_finishedfires instantly, butbet_amount_todayin that payload may still be0. Use threshold conditions (> X), not exact equality (= N), when building on DWH aggregate fields.You can combine multiple conditions with AND. The campaign fires only when all are true, which lets you be precise about who gets what offer at exactly the right moment.
-
Design and launch the campaign
Choose your channel and craft the message. For triggered campaigns the timing is automatic — the campaign fires the moment conditions are met. No scheduling needed.
In-app popup
Best while the player is in session.
In-app toast
A brief, dismissible banner — lighter-touch than a popup, no click required.
Push notification
Reaches them whether or not they are on site.
Email
Works, but the moment has passed by the time they open it.
SMS
High reach, high cost. Reserve for high-value moments.
Target group guide Building target groups that work
Not all attributes are equal. Some give reliable segments from day one; others need sufficient player history before they mean anything. Getting this wrong means campaigns firing to the wrong people.
Start every triggered campaign with this base TG
These four filters keep you compliant, exclude the wrong audience, and ensure campaigns reach reachable players only. Add extra filters on top.
- Country = US (or target markets)
- Is Blocked = No
- Allow Email or Allow Push = Yes
- Player Type = Existing / Visitor
Statistical gotchas — when attributes mislead you
Some attributes only make sense after a player has enough history. Using them too early produces garbage segments and campaigns that fire to the wrong people.
Average purchase amount
One large outlier purchase completely skews the average for players with few transactions. A player who bought once at $50 has an "average" of $50 — a sample of one, not a behavioural signal.
Add Number of Purchases, Lifetime ≥ 5 first.
Cashout ratio
A player with one redemption has either a 0% or 100% ratio — mathematically correct but statistically useless. You cannot segment meaningfully on ratios with 1–2 data points.
Add Number of Redeems, Lifetime ≥ 3 first.
Churn probability score
Optimove's churn model needs months of behavioural history to be accurate. Players who registered recently produce unreliable scores that may cause you to target — or exclude — the wrong people.
Add Months Since Registration ≥ 3 first.
SC win ratio
Win ratios fluctuate wildly with small sample sizes. A player who won 5 of their first 7 bets looks like a 71% winner — that is pure variance, not a reliable signal.
Only meaningful with Number of Bets Made ≥ 20.
Frequency, last 3 months
This measures activity over the last 90 days. For a player registered 20 days ago, "last 3 months" is mostly empty — the frequency will be misleadingly low and segment them incorrectly.
Add Days Since Registration ≥ 90 first.
Percentile vs raw amounts
Raw purchase amounts like "lifetime total > $50" mean different things depending on how long a player has been registered. A 2-week player at $50 and a 2-year player at $50 are very different segments.
Prefer Purchase Percentile By LCS over raw
Total Purchase Amount.
Both values change over time. Putting them in a target group means Optimove
evaluates them at an unknown time against stale batch data — by the time an event
fires, TG membership may not reflect the player's current state. Put
risk_score < 70 or redemption_rate < 75% in the
trigger condition, which reads the live value from the event
payload at the exact moment it fires.
Event reference Complete event catalogue
Every event Swivel sends to Optimove, with real production payloads. Fifteen events across two transports: ten sent backend to backend, five fired by the Optimove browser SDK.
Backend events
Sent server to server. Unaffected by ad blockers. Every one of these carries the common context block documented at the end of this section.
sign_up
Once · after registration- type_of_registration
- country_code
- state_code
- promo_code
- referred_by_id
- affiliate_id
- marketing_id
No DWH aggregates — the user is brand new. Balances are 0, and there is no purchase or bet history yet.
"type_of_registration": "email"
"country_code": "IE"
"promo_code": "N/A"
"referred_by_id": "N/A"
"affiliate_id": "N/A"
"gc_balance": 0
"sc_balance": 0
"xp_total": 0
deposit
Every completed purchase- deposit_id
- deposit_in_usd
- is_first_time_deposit
- original_deposit
- original_currency
- payment_method
- requested_deposit
- sw_package_id
- sw_package_type
purchase_count_* may not yet reflect this deposit — the DWH lags
~30s. See the user_active recommendation.
"deposit_in_usd": 2.99
"is_first_time_deposit": false
"payment_method": "creditCard"
"sw_package_type": "standard"
"purchase_count_lifetime": 3 // may still read 2
"purchase_count_30d": 2
"purchase_amount_lifetime": 2.97
"sc_balance": 12232.78
bet_finished
Every bet round- game_id
- game_type
- provider_id
- amount_in_usd
- amount_won_in_usd
- original_amount
- original_currency
- multiplier
- is_winning_bet
bet_amount_* and win_amount_* may lag ~30s.
High-frequency event — fires on every single bet.
"game_id": "dice"
"game_type": "originals"
"amount_in_usd": 1250
"amount_won_in_usd": 1212.12
"is_winning_bet": true
"multiplier": 0.9697
"bet_amount_30d": 73654.47
"sc_balance": 12232.78
level_change
On level up- level_experience_threshold
Best event for level-gated campaigns. No DWH lag concerns for level itself.
"level_name": "Yellow Gold 2"
"level_rank": "Yellow Gold"
"level_experience_threshold": 7500
"xp_total": 7574.24
"xp_to_next_level": 2425.76
"sc_balance": 12232.78
bonus_claim
When a bonus is claimed- bonus_id
- bonus_name
- bonus_type
- claimed_amount
- claimed_currency
- free_spin_count
- user_bonus_id
bonus_type is "cash" or "freeSpins".
For free spins claimed_amount is null and
free_spin_count carries the value.
"bonus_name": "CashCash20"
"bonus_type": "cash"
"claimed_amount": 20
"claimed_currency": "gc"
"free_spin_count": null
"bonus_claimed_30d": 11.02
"bonus_name": "FreeSpin"
"bonus_type": "freeSpins"
"claimed_amount": null
"claimed_currency": null
"free_spin_count": 100
redemption_requested
Cashout submitted- payout_id
- requested_amount
- requested_currency
Use for retention plays: the player has intent to withdraw — consider a
purchase incentive if sc_balance is low after the redemption.
"requested_amount": 10
"requested_currency": "sc"
"sc_balance": 12232.78
"pending_redemption_amount_in_usd": 0
"completed_redemption_count_lifetime": 6
redemption_completed
Payout clears · backend- payout_id
- requested_amount
- requested_currency
- paid_out_amount
- paid_out_currency
Fires from a backend process, not a player action. Good for a "your withdrawal cleared" follow-up — but the player is probably not in session, so use email or push, never a popup.
"requested_amount": 10
"requested_currency": "sc"
"paid_out_amount": 0.00473139
"paid_out_currency": "eth"
"completed_redemption_count_30d": 5
"completed_redemption_amount_lifetime": 55
user_active
Every ~2 min in sessionBy the time this fires, about 2 minutes after the last activity, all aggregate fields have settled in the DWH. Read the full recommendation →
// Only common context — same fields as every other event
"purchase_count_lifetime": 3 // settled
"bet_amount_30d": 73654.47 // settled
"sc_balance": 12232.78
"level_name": "Yellow Gold 2"
"xp_total": 7574.24
initial_daily_balance
Once per day · first sessionUseful for daily check-in campaigns and day-start balance nudges. Fires once per player per calendar day on their first login.
// Same context as user_active — full aggregate snapshot
"sc_balance": 12232.78
"purchase_count_today": 0
"bet_amount_today": 13750.20
"login_count_7d": 3
promo_award_selected
Player picks a promo offer- award_id
- promo_id
Frontend-triggered, backend-relayed:
POST crm/events/select-offer → queue → worker → Optimove. Because it
is relayed server to server, ad blockers cannot suppress it.
No production sample captured yet — fields below are per the backend DTO.
Carries database enrichment only: no DWH aggregates and no
risk score, the same shape as sign_up.
"award_id": "a1a4a2ba-2f1e-4b6c-9ad2-6c0a8d51e4f7"
"promo_id": "7f3c9e28-4d51-4a0e-b6c9-8e2d1f0a5b34"
"gc_balance": 41158
"sc_balance": 12232.78845139062
"level_name": "Yellow Gold 2"
"level_rank": "Yellow Gold"
"pending_redemption_amount_in_usd": 0
"xp_total": 7574.2387711363635
"xp_to_next_level": 2425.7612288636365
Frontend SDK events
These are fired by the Optimove browser SDK from the player's own device — the only events that do not go server to server. A share of them is suppressed by ad blockers and privacy extensions. Do not build a campaign whose correctness depends on one of these firing for every player.
set_user_id_event
Identity
Binds the anonymous visitor ID the SDK has been using to the authenticated player ID. Fires in the sign-up and login sequence. Everything the visitor did before this point is stitched onto the player profile.
"userId": "57affc85-0776-4f30-ae92-4a1c38ca58f9"
"originalVisitorId": null
"updatedVisitorId": null
set_email_event
Identity
Sets the player's email on the Optimove profile from the browser. Fires in the
sign-up sequence alongside set_user_id_event.
"email": "regms61e418242ca1@test.swivelgaming.com"
set_page_visit_event
Navigation
Fires on each page view. This is the event Optimove needs to display an in-app popup: a popup can only be rendered on a live frontend page event, so any popup campaign must include a page visit in its trigger sequence.
No captured sample. Carries the SDK's standard page context.
cashier_exit
Abandonment · Phase 4, v3.73
Fires when the player closes the cashier without completing a purchase. The abandonment signal behind scenario 15.
Frontend event — ad blockers suppress a percentage of fires. Treat any cashier-abandonment campaign as best-effort coverage.
pwa_install
Engagement
Fires when the player installs the site as a progressive web app on their device. A strong engagement signal — installers are materially more likely to return.
No captured sample.
Common context
All DWH-sourced aggregate fields below are available in every event as campaign conditions. They are sourced from ClickHouse and carry a ~30-second lag behind the action that fires the event.
Field index
- purchase_count_lifetime
- purchase_count_30d
- purchase_count_7d
- purchase_count_today
- purchase_amount_lifetime
- purchase_amount_30d
- purchase_amount_7d
- purchase_amount_today
- bet_amount_30d
- bet_amount_7d
- bet_amount_lifetime
- bet_amount_today
- win_amount_30d
- win_amount_7d
- win_amount_lifetime
- win_amount_today
- completed_redemption_count_30d
- completed_redemption_count_lifetime
- completed_redemption_amount_30d
- completed_redemption_amount_7d
- completed_redemption_amount_lifetime
- redemption_rate_lifetime
- bonus_claimed_30d
- bonus_claimed_lifetime
- sc_balance
- gc_balance
- pending_redemption_amount_in_usd
- net_purchase_lifetime
- level_name
- level_rank
- level_id
- xp_total
- xp_to_next_level
- login_count_7d
- risk_total_risk_score
- are_email_notifications_enabled
- are_phone_notifications_enabled
- user_id
- user_email
- event_id
If your campaign condition checks any DWH field above, read the user_active recommendation before choosing your trigger event.
Critical guideline Use user_active for DWH-aggregate campaigns
Campaigns triggered by action events and filtered on DWH aggregates are fundamentally unreliable. Here is why, and the right approach.
Do not do this
Do not trigger on action events when your condition checks aggregate counts. The data warehouse that populates purchase_count_lifetime, bet_amount_30d and the rest has a ~30-second propagation delay. When a deposit event fires, the DWH aggregate for that same deposit has almost certainly not updated yet. Sometimes it has, sometimes it has not — which makes the campaign non-deterministic.
Concrete example — fire when a player makes their 3rd deposit
Wrong — trigger on deposit
-
T+0:00
Player completes their 3rd deposit.
-
T+0:00
depositfires instantly to Optimove. -
T+0:00
Optimove reads
purchase_count_lifetime = 2. The DWH has not caught up. -
T+0:00
Condition
≥ 3fails. The campaign does not fire. -
T+0:30
DWH catches up: the count is now 3, but the event moment has passed.
The campaign silently fails. On other occasions the DWH updates in time, so it fires some of the time but not always.
Right — trigger on user_active
-
T+0:00
Player completes their 3rd deposit.
-
T+0:30
DWH catches up:
purchase_count_lifetime = 3. -
T+~2:00
user_activefires on its heartbeat. -
T+~2:00
Optimove reads
purchase_count_lifetime = 3— settled. -
T+~2:00
Condition
≥ 3passes. Campaign fires.
Fires within about 2 minutes of the 3rd deposit, every time. The delay is invisible to the player and eliminates the race condition.
How user_active solves the problem
-
Set the trigger event to user_active
user_activefires roughly every 2 minutes while the player is active in a session. It is controlled by a server heartbeat with Redis dedup, so it fires at most once per interval per user. By the time it fires, the DWH has had ample time to process any preceding action. -
Add your aggregate threshold as a trigger condition
Use any DWH aggregate as the condition —
purchase_count_lifetime >= 3,bet_amount_30d >= 1000, orcompleted_redemption_count_lifetime >= 5. These values are guaranteed to be settled by the timeuser_activefires. -
Gate correctly — the right cap depends on your condition shape
Because
user_activefires repeatedly, the campaign will re-fire on every heartbeat as long as the condition is true. How you cap it depends on whether the condition can ever become false again.Open-ended threshold
>= Xon a lifetime counterpurchase_count_lifetime >= 3is true forever once crossed. The only valid gate is once per user lifetime. A 30-day cooldown is wrong: after 30 days the player still has ≥ 3 lifetime deposits and the campaign fires again.Bounded range
>= X AND <= YThe player eventually exits the range, so the condition becomes false on its own. A time-based cooldown can work here — but confirm the business intent. If it is "first time ever," use a lifetime gate regardless.
When to use each trigger approach
Follow this decision table every time you design a new event-triggered campaign.
Use the action event
Your condition uses only the event's own fields, not DWH aggregates. These are set at the moment the event fires — no lag.
- deposit_in_usd > 50
- is_first_time_deposit = true
- game_id = "crash"
- bonus_type = "freeSpins"
- sc_balance < 10
Use user_active
Your condition relies on any DWH aggregate count or amount. These read from ClickHouse and lag ~30s behind the triggering action. Always pair with a per-user frequency cap.
- purchase_count_*
- bet_amount_*
- win_amount_*
- completed_redemption_count_*
- bonus_claimed_*
Use a Repeated event
You want to trigger on the Nth occurrence of the event itself.
Optimove counts occurrences internally from when the player enters the trigger —
no DWH involved. Reliable, and it does not need user_active.
For a time window ("3 bets within 1 hour"), add the event multiple times in the trigger sequence and set the timeframe at the bottom; a single "Occurred N times" condition has no time window.
Practical campaign examples using user_active
Reward after 3rd deposit ever
- Trigger
user_active- Condition
purchase_count_lifetime >= 3- Guard
- Once per user lifetime
- Why
- DWH aggregate — needs a settled value
High-value bettor, $1,000 in 30d
- Trigger
user_active- Condition
bet_amount_30d >= 1000- Guard
- Once per user per 30 days
- Why
- Fires on every heartbeat once the threshold is passed
Fifth redemption loyalty bonus
- Trigger
user_active- Condition
completed_redemption_count_lifetime >= 5- Guard
- Once per user lifetime
- Why
- Count not reliable on
redemption_completed
Bonus spender milestone, $50+
- Trigger
user_active- Condition
bonus_claimed_lifetime >= 50- Guard
- Once per user lifetime
- Why
- Bonus totals lag behind claim events
First deposit ever
Action event — no DWH needed
- Trigger
deposit- Condition
is_first_time_deposit = true- Guard
- None — boolean, fires once
- Why
- Event's own field — fires reliably
Low balance after a bet
Action event — live field
- Trigger
bet_finished- Condition
sc_balance < 10- Guard
- Per-user cooldown, e.g. 1/day
- Why
sc_balanceis live, not DWH
Campaign scenarios 20 scenarios, ready to build
Grouped by trigger mechanism. Every triggered scenario fires from a live event — conditions are checked on the payload, not in the target group.
- Simple event
- Repeated event
- Uncompleted sequence
- Scheduled
Triggered · simple events
Deposit upsell
Goal — player buys a standard $10 pack, show a $20 special offer while they are still in the cashier flow
- Event
deposit, the moment a purchase completes- TG
- Existing / new (visitor) · not banned · opted in · country = US
- Condition
-
purchase_amount = 10.00ANDis_first_time_deposit = false - Fires
- In-app popup or push: special $20 offer with extra SC bonus
Balance drop
Goal — mid-tier buyer drains their SC mid-session, nudge with a top-up matching their usual spend
- Event
bet_finished, after every bet resolves- TG
- Existing · not banned · opted in · avg_purchase $4.99–$9.99 with ≥5 purchases
- Condition
sc_balance < 1- Fires
- Top-up offer personalised to their spend tier
avg_purchase is a batch attribute — it belongs in the TG filter,
not the trigger condition. Only include players with ≥5 purchases so the
average is statistically meaningful.
Redemption requested
Goal — player submits a cashout with almost no SC left, encourage a purchase before they disengage
- Event
redemption_requested- TG
- Existing / new (visitor) · not banned · opted in
- Condition
sc_balance < 2after the request- Fires
- "Top up while your cashout processes"
Bonus claimed
Goal — player claims a bonus, ride the engagement momentum with a follow-up offer
- Event
bonus_claim- TG
- Existing / new (visitor) · not banned · opted in
- Condition
risk_score < 70— exclude bonus abusers- Fires
- "Make the most of your bonus coins"
risk_score is null for a new user (visitor) — not defined.
Bet finished, empty pockets
Goal — SC hits zero after a bet, offer a top-up but exclude likely bonus abusers
- Event
bet_finished- TG
- Existing / new (visitor) · not banned · opted in
- Condition
sc_balance < 1ANDrisk_score < 70- Fires
- Top-up offer, hidden from high-risk players
risk_score is null for a new user (visitor) — not defined.
First purchase ever
Goal — any player makes their very first purchase, fire a first-time buyer welcome
- Event
deposit, on every purchase- TG
- Existing / new (visitor) · not banned · opted in
- Condition
is_first_time_deposit = true- Fires
- Welcome campaign with bonus coins or a special pack
For brand-new users registered today, you can also use a Visitor TG plus the
sign_up → deposit uncompleted sequence — see scenario 13.
Level up celebration
Goal — player levels up, celebrate and tease what is coming at the next level
- Event
level_change, on every level-up- TG
- Existing / new (visitor) · not banned · opted in
- Condition
- None — every level-up is worth celebrating
- Fires
- Congratulations popup plus next-level perks and XP threshold
Almost at next level
Goal — player is close to levelling up, motivate with an XP-progress nudge
- Event
bet_finished, after every bet- TG
- Existing / new (visitor) · not banned · opted in
- Condition
-
xp_to_next_level < 100— threshold to confirm with product - Fires
- "You're only X XP away from [next level]"
Big win moment
Goal — player wins big, capitalise on high positive emotion
- Event
bet_finished, after every bet- TG
- Existing / new (visitor) · not banned · opted in
- Condition
-
is_winning_bet = trueANDamount_won_in_usd > 50 - Fires
- "Congrats on your big win — ready to ride the streak?"
Redemption completed
Goal — player just got paid out, re-engage while goodwill is at its peak
- Event
-
redemption_completed, when the cashout is approved and paid - TG
- Existing / new (visitor) · not banned · opted in
- Condition
sc_balance < 5- Fires
- "Your cashout is on its way — here's a bonus pack"
This fires when the admin approves and the external payment system completes the payout. That is asynchronous — the player is likely not in session.
Triggered · repeated events
4th purchase today
Goal — player has already bought 3 times today, reward their 4th with a loyalty perk
- Event
deposit, configured as Repeated- TG
- Existing / new (visitor) · not banned · opted in
- Condition
-
deposit × 4in the trigger sequence, 24h timeframe at the bottom - Fires
- VIP loyalty reward — bonus coins or exclusive pack
Add the deposit event 4 times in the trigger sequence, then set the 24h timeframe at the bottom. Do not use "Occurred 4 times" — it has no time window.
3 bets in a row
Goal — player places 3 bets in a session, reward their momentum with a bonus
- Event
bet_finished, configured as Repeated- TG
- Existing / new (visitor) · not banned · opted in
- Condition
-
bet_finished × 3within 60 min, plusrisk_score < 70 - Fires
- "You're on a roll — here's a bonus bet"
Add bet_finished 3 times with a 60-minute timeframe at the bottom. For strict
consecutive detection with no other events in between, use Optimove Streams.
risk_score is null for a new user (visitor).
Triggered · uncompleted sequence
Registered, no purchase
Goal — new player signed up but has not bought anything, catch them while warm
- Event
-
A:
sign_up· B expected:deposit· window 30 min - TG
- Visitors, new users today · not banned · opted in
- Condition
-
If
depositdoes not fire within 30 min aftersign_up - Fires
- "Your first purchase comes with X bonus coins — expires in 1 hour"
Requires the uncompleted sequence event configured in Optimove BO first.
Deposited, no bet
Goal — player bought coins but has not placed a bet, bridge purchase and play
- Event
-
A:
deposit· B expected:bet_finished· window 15 min - TG
- All users · not banned · opted in
- Condition
-
If
bet_finisheddoes not fire within 15 min afterdeposit - Fires
- "You've got coins — try [featured game]"
Requires the uncompleted sequence event configured in Optimove BO first.
Cashier exit, no purchase
Goal — player opened the coin store but left without buying. Two approaches, depending on urgency.
- Event
-
cashier_exit, when the user closes the cashier without buying - TG
- All users · not banned · opted in
Option A — immediate
No condition. The event already signals abandonment, so the campaign fires immediately. Popup or push, since the player is still in session.
Option B — give them a chance
A: cashier_exit · B expected: deposit · window 10–15
min. If no deposit follows, the campaign fires. Push or email, since the
player may have left.
cashier_exit is a frontend event — ad blockers suppress a
percentage of fires. Option B also requires the uncompleted sequence
configured in Optimove BO first.
Scheduled · inactive players
Scheduled campaigns run on the nightly snapshot and can reach inactive players. Unlike triggered campaigns, target groups can include richer filters here — the batch data is fresh enough for players who have not been active recently.
Win-back, 7 days inactive
Goal — players who were active but have not logged in for 7+ days, bring them back before they churn
- Event
- None — scheduled campaign at a fixed time
- TG
- Existing · not banned · opted in · Days Since Last Login ≥ 7 AND ≤ 30 · Total Purchase Amount, Lifetime > $10
- Condition
- None — TG filters define the audience
- Fires
- Email at 5am: "We miss you — here's 500 free GC"
The Total Purchase Amount filter focuses on players who have previously spent — non-spending players rarely reactivate from win-back emails.
High churn risk
Goal — players Optimove's AI predicts are about to churn, pre-emptive retention offer
- Event
- None — scheduled campaign sent daily
- TG
- Existing · not banned · opted in · Churn Probability Score > 70 · Days Since Last Activity ≥ 3 · registered more than a few days ago
- Condition
- None — TG filters define the audience
- Fires
- Email at 11am: personalised retention offer
When using Churn Probability Score, filter on time since registration. Players registered only a few days ago do not have enough history for the score to be meaningful.
Phase 2 · DWH aggregates
These scenarios use DWH aggregate fields now embedded in every event payload. All windowed metrics are grouped by UTC calendar day, not rolling windows. "Today" means the current UTC day; "7d" means the last 7 calendar days from UTC midnight.
A player makes their 3rd deposit. The deposit event fires instantly,
but purchase_count_lifetime inside that same payload may still read
2, so purchase_count_lifetime >= 3 fails and the
campaign silently misses. On other occasions the DWH has already updated, which
makes the trigger non-deterministic.
Solution: trigger on user_active instead. It fires
every ~2 minutes while the player is active, by which point the DWH has settled.
Scenarios 18 and 20 do exactly this.
Gating rule: for open-ended thresholds (>= X on a
lifetime counter) gate once per user lifetime — the condition never
becomes false again. For bounded ranges (>= X AND <= Y) a
time-based cooldown is acceptable, since the player will eventually exceed Y.
High wager volume today
Goal — player has wagered a large amount today, reward engagement before they stop
- Event
user_active, every ~2 min while active- TG
- Existing · not banned · opted in
- Condition
-
bet_amount_today >= 50000 SC— threshold to define with product - Fires
- Loyalty reward or VIP offer — "you've been on a roll today"
Use user_active, not bet_finished.
bet_amount_today is a DWH aggregate and lags ~30s.
Gate: once per UTC day per player —
bet_amount_today resets at UTC midnight.
Standard pack → premium upsell
Goal — player just bought a standard pack, upsell to premium while they are in a buying mindset
- Event
user_active, every ~2 min while active- TG
- Existing / new (visitor) · not banned · opted in
- Condition
sw_package_type = "standard"- Fires
- Popup — "upgrade to premium and get 2× the SC for $X more"
Combine with is_first_time_deposit = false to exclude first-time
buyers — they have a separate welcome campaign, scenario 06.
Purchase milestone
Goal — player crosses a lifetime purchase count milestone, reward loyalty with a surprise bonus
- Event
user_active, every ~2 min while in session- TG
- Existing · not banned · opted in
- Condition
purchase_count_lifetime >= 10- Fires
- "Thank you for your 10th purchase — here's a loyalty bonus"
Use user_active, not deposit.
purchase_count_lifetime is a DWH aggregate.
Gate: once per user lifetime. The threshold
>= 10 is true forever once crossed — a time-based cap would
re-fire the campaign indefinitely.
Release status
All 20 scenarios live- Phase 1
- v3.73–3.76 — new events (redemption_requested, redemption_completed, bonus_claim) and Postgres enrichment on all events. Covers scenarios 1–14, 16–17, 19.
- Phase 4
- v3.73 —
cashier_exitfrontend event. Covers scenario 15. - Phase 2
-
v3.74 — DWH aggregate enrichment on all events plus the
user_activeheartbeat. Unlocks scenarios 18 and 20. All DWH aggregate values lag ~30s.
Summary Everything together
The two channels serve different players at different moments.
| Topic | Batch / scheduled | Events / triggered |
|---|---|---|
| Who it targets | All players, including inactive | Primarily active players — but backend-triggered events, such as redemption_completed, can reach any player |
| Data freshness | Yesterday's snapshot | The moment it happened |
| Update frequency | Once per night | Every action, every time |
| Campaign timing | Scheduled, e.g. 5am | Instant, seconds after the action |
| Best use case | Reactivation, win-back, loyalty | Upsell, celebration, follow-up |
| Do they affect each other? | No. Completely independent channels. Events never update batch data. | |
Where each piece sits
-
Data sources
Player database, transaction history, and game activity — plus the player action that fires an event.
-
Inside Optimove
Profiles updated nightly for all players; target groups evaluated at an unknown time on static filters; and the real-time event stream.
-
Output
Scheduled campaigns fire at a set time to inactive players. Triggered campaigns fire instantly to active ones.