Why your island gets rejected by rule 4.4.9 even with PaidRandomItem = true

If your island keeps getting rejected with a “Skipped Island Review” citing rule 4.4.9 even though you already have PaidRandomItem = true set on your entitlement, this post is for you. The reviewer never tests in-game, they reject it straight from the metadata.

After several rejected submissions, I found the real cause and want to share it.

The problem

I had a paid random item (lootbox-style entitlement bought with V-Bucks). The entitlement was correctly defined with PaidRandomItem = true:

my_random_entitlement<public> := class<concrete>(entitlement):
    var Name<override> : message = my_random_name
    var Icon<override> : texture = my_icon
    MaxCount<override> : int = 200
    Consumable<override> : logic = true
    PaidRandomItem<override> : logic = true       // already set
    ConsequentialToGameplay<override> : logic = true

The offer was also fine, so in theory everything was correct and yet, rejected over and over again.

What was actually wrong

I was also granting the SAME entitlement when the player obtained the item through normal gameplay (not from a paid purchase). I was using the entitlement count as a progress tracker, so on every legit acquisition I called:

// WRONG — granting a PaidRandomItem entitlement outside the paid flow
GrantFromGameplay(Player:player)<suspends>:void=
    Granted := GrantEntitlement(Player, my_random_entitlement)
    if (Granted?){}

Even though it was only being used internally as a counter, Epic’s automated moderation reads every GrantEntitlement call on a PaidRandomItem and flags it if it happens outside a V-Bucks transaction. That’s an instant 4.4.9 rejection, no in-game review needed.

The fix

Only call GrantEntitlement for PaidRandomItem entitlements inside the actual paid purchase flow:

// CORRECT — only granted from a successful BuyOffer
TryBuyRandom(Player:player)<suspends>:void=
    Bought := BuyOffer(Player, my_random_offer{})
    if (Bought?):
        spawn{GrantFromPaidFlow(Player)}   // OK here, paid flow

For tracking progress / counts from normal gameplay, use your own persistable data instead of the entitlement:

my_profile_data := class<final><persistable>:
    UnlockedItems : []string = array{}
    // ...

UnlockedItems.Length gives you the same count without touching the paid entitlement.

After making this change, my island was approved on the next submission.

TL;DR

If you have a PaidRandomItem entitlement and you’re getting rejected even with PaidRandomItem = true set, check that you are never calling GrantEntitlement on it from non-paid gameplay flows. Even using it as an internal counter triggers the 4.4.9 flag. Track gameplay progress with your own persistable data.

My opinion

Honestly I think this behavior is wrong. The whole point of having MaxCount on an entitlement is to be able to track how many of that item the player has — including ones they got outside of a paid transaction. Otherwise, why even have MaxCount if you can only ever grant it via BuyOffer?

It would make a lot more sense if Epic’s moderation flagged unpaid grants only when PaidRandomItem = true AND the entitlement was being granted at scale without purchases, instead of blocking it entirely. Right now you’re forced to maintain TWO separate counters (the paid entitlement + your own persistable data) for the same item, which is just unnecessary complexity.

Hope this saves someone a few days. :folded_hands: