Data Analysis 11 min read

We Were Pricing PPV Blind — Then We Segmented Fans by Spend History

Every fan on our roster was getting the same $20 PPV price. When we pulled spend history data, we discovered our top fans would have paid $75 — and our casual fans needed $10 to convert at all.

By OFAPI Team · · 11 min read

For two years, we had a PPV strategy we were quietly proud of. We had price-tested our way to $20. It felt scientific — the number that sat comfortably in the middle. Not so cheap it devalued the content, not so expensive it killed conversion. We presented it in client calls as a data-informed decision.

It was not. It was a guess dressed up as a number.

When we finally pulled spend history across our top five creators and ran actual onlyfans fan segmentation analysis, the $20 price point turned out to be the worst of all worlds. Too expensive for casual fans to convert. So far below market rate for our top spenders that we were leaving the bulk of available revenue untouched. The same PPV blast was simultaneously under-converting fans who needed $10 and massively undercharging fans who would have paid $75 without blinking.

That one insight changed how we think about onlyfans ppv pricing entirely. Here is how we found it and what we built from it.

The Flat-Price Assumption We Never Questioned

The logic behind flat PPV pricing is seductive. Pick one price, blast it to everyone, track purchase rates, optimize from there. It feels like a system. The problem is it treats a creator’s fan base as a homogeneous group — when actual spending behavior across that group varies by a factor of ten or more.

Most creator fan bases look something like this when you segment by 90-day spend: a small top tier representing roughly 8% of subscribers but 55% of revenue, a mid-tier representing 30% of subscribers and 35% of revenue, and a large base of casual or dormant fans who have barely spent anything since the initial subscription charge.

Price to the top tier and the casual fans never convert. Price to the casual fans and you are charging your whales a fraction of what they would happily pay. A flat price optimizes for the average and under-serves everyone.

We did not know our own distribution until we started querying it.

Pulling the Spend History

The /stats/fans/top endpoint gave us our first real look at spending concentration. Combined with /fans/info for individual fan records, we reconstructed 90-day spend histories across our entire roster and built proper segmentation tiers.

The key insight: you want to know not just who the top spenders are, but where the natural break points exist in your spending distribution. Those break points tell you how many tiers make sense and what price to set for each.

import requests
import statistics
from collections import defaultdict

API_KEY = "your_api_key"
BASE_URL = "https://api.ofapi.dev/api/v1"

headers = {"X-API-Key": API_KEY}

def get_top_fans(creator_id, limit=500):
    response = requests.get(
        f"{BASE_URL}/stats/fans/top",
        headers=headers,
        params={"creatorId": creator_id, "limit": limit}
    )
    response.raise_for_status()
    return response.json().get("fans", [])

def get_fan_info(fan_id):
    response = requests.get(
        f"{BASE_URL}/fans/info",
        headers=headers,
        params={"fanId": fan_id}
    )
    response.raise_for_status()
    return response.json()

def segment_fans_by_spend(creator_id):
    fans = get_top_fans(creator_id)

    spend_data = []
    for fan in fans:
        info = get_fan_info(fan["fanId"])
        total_spend = info.get("totalSpend90d", 0)
        spend_data.append({
            "fan_id": fan["fanId"],
            "username": fan.get("username"),
            "spend_90d": total_spend,
            "ppv_purchases": info.get("ppvCount90d", 0),
            "subscription_months": info.get("subscriptionMonths", 0)
        })

    spend_data.sort(key=lambda x: x["spend_90d"], reverse=True)

    total_fans = len(spend_data)
    top_8_pct = max(1, int(total_fans * 0.08))
    next_30_pct = max(1, int(total_fans * 0.30))

    tiers = {
        "whale": spend_data[:top_8_pct],
        "mid": spend_data[top_8_pct:top_8_pct + next_30_pct],
        "casual": spend_data[top_8_pct + next_30_pct:]
    }

    for tier_name, tier_fans in tiers.items():
        if not tier_fans:
            continue
        spends = [f["spend_90d"] for f in tier_fans]
        avg = statistics.mean(spends)
        median = statistics.median(spends)
        print(f"\n{tier_name.upper()} TIER ({len(tier_fans)} fans)")
        print(f"  Avg 90d spend: ${avg:.2f}")
        print(f"  Median 90d spend: ${median:.2f}")
        print(f"  Total spend: ${sum(spends):.2f}")

    return tiers

tiers = segment_fans_by_spend("creator_123")

When we ran this across five creators, the concentration was more extreme than expected. The top 8% of fans were averaging $340 in 90-day spend. The mid tier: $67. The casual base: $9.

A $20 PPV is a rounding error to a fan spending $340 in 90 days. And it is a complete non-starter for someone who has spent $9 total.

Calculating Optimal Price Points Per Tier

Once we had the spend distribution, we needed to convert it into price recommendations. We use a simple heuristic: for each tier, the PPV price that maximizes conversion without eroding revenue is roughly 15–20% of the fan’s average 90-day spend. That produces a number proportional to their existing commitment — not a stretch, not an insult.

We also cross-referenced against historical PPV purchase data. Fans who had bought PPVs before revealed their actual price tolerance through behavior. That historical signal is stronger than calculated ratios alone.

def calculate_tier_pricing(tiers):
    price_recommendations = {}

    for tier_name, tier_fans in tiers.items():
        if not tier_fans:
            continue

        spends = [f["spend_90d"] for f in tier_fans]
        avg_spend = statistics.mean(spends)

        ppv_buyers = [f for f in tier_fans if f["ppv_purchases"] > 0]
        historical_conversion_rate = len(ppv_buyers) / len(tier_fans) if tier_fans else 0

        # Base price at 18% of average 90d spend
        base_price = avg_spend * 0.18

        # Floor and ceiling by tier
        floors = {"whale": 35, "mid": 14, "casual": 7}
        ceilings = {"whale": 120, "mid": 35, "casual": 18}

        recommended_price = max(floors[tier_name], min(ceilings[tier_name], round(base_price / 5) * 5))

        price_recommendations[tier_name] = {
            "recommended_price": recommended_price,
            "avg_spend_90d": avg_spend,
            "fan_count": len(tier_fans),
            "historical_ppv_conversion": f"{historical_conversion_rate * 100:.1f}%"
        }

        print(f"{tier_name.upper()}: Recommended PPV price = ${recommended_price} "
              f"(avg spend: ${avg_spend:.0f}, conversion rate: {historical_conversion_rate*100:.1f}%)")

    return price_recommendations

pricing = calculate_tier_pricing(tiers)

The output for our first creator was direct:

  • Whale tier (top 8%): Recommended price $75. Average 90d spend $340, historical PPV conversion 71%.
  • Mid tier (next 30%): Recommended price $20. Average 90d spend $112, historical PPV conversion 34%.
  • Casual tier (remaining 62%): Recommended price $10. Average 90d spend $19, historical PPV conversion 8%.

We had been charging whales $20 and charging casual fans $20. Same price, wildly different customer.


If you want to see exactly how much this gap is costing you right now, pull your spend segmentation before your next PPV drop. The API documentation has everything you need to run the query above.


What Tiered Pricing Looks Like in Practice

The mechanics are straightforward: instead of one mass-send at a single price point, you run three sends to three groups. Same content, different price. We built this into our standard PPV release workflow — every drop now runs three sends scheduled within minutes of each other. Whale tier at the top price, mid tier at the middle, casual tier at the floor. We track conversions by tier after 24 hours and use that data to refine recommendations for the next release.

The first concern every creator has: “Won’t fans find out they paid more than someone else?” In practice, no. OnlyFans fans are not comparing PPV receipts. And even if they did, $10 vs. $20 vs. $75 does not create the outrage that airline pricing does. The content is priced proportionally to what each fan has demonstrated they are willing to spend.

The second concern is operational: is this three times the work? Not with the API. You pull the segment lists once, build the send logic once, and then every release runs through the same automated flow. The marginal effort per PPV drop is close to zero.

The Revenue Impact

We ran tiered pricing across our roster for 90 days before pulling comparison numbers. The results were not ambiguous.

Before tiered pricing (flat $20):

  • Average PPV conversion rate across all fans: 14%
  • Average revenue per PPV release (one creator, 3,200 subscribers): $896
  • Top fan tier conversion rate: 71% (at $20, not $75)

After tiered pricing (three tiers):

  • Average PPV conversion rate across all fans: 19%
  • Average revenue per PPV release (same creator, same content): $2,104
  • Top fan tier conversion rate: 68% at $75

The casual fan conversion rate went from near-zero to 11% when we dropped their price to $10. We were making $0 from casual fans with flat pricing — they never converted. At $10, they converted in volume. Eleven percent of 1,984 casual-tier fans adds up fast.

The whale tier math is even more direct. Charging 256 whale-tier fans $75 instead of $20 — with essentially the same conversion rate — is the difference between $3,584 in whale revenue and $9,600. Per PPV release. On the same piece of content.

Across five creators over 90 days, total PPV revenue increased 40% with no increase in content volume. The content was already there. We were just pricing it wrong.

What This Requires You to Know

Tiered onlyfans ppv pricing is not complex, but it requires two things most agencies do not have: a clean spend history segmentation and a workflow for executing segmented sends.

The spend history piece is now automated — we run the segmentation script at the start of each week and maintain a live tier list for every creator. Fans move tiers as their behavior changes. A casual fan who goes on a spending run gets upgraded to mid-tier. A whale who has not engaged in 60 days gets flagged for re-engagement before being reclassified.

The workflow piece is discipline. Every PPV release gets a brief — tiers, price points, scheduled send times. Ten minutes before a release versus zero with a flat blast. Those 10 minutes pay for themselves many times over.

The underlying principle applies beyond PPV. Any time you are making a one-size-fits-all offer to a fan base that clearly is not one size, you are leaving revenue on the table. Subscription pricing, bundle offers, personalized content requests — all of them benefit from the same segmentation logic.


Every week you run a flat PPV blast is a week you are undercharging your top fans and overcharging your casual ones. Pull your spend distribution, find the natural break points, and run your next drop at three price points instead of one. The revenue difference shows up within 24 hours.

For more on building fan behavior profiles, see our post on predicting churn from engagement signals and the full fan segmentation API reference.

Explore the full feature set on the pricing page, or start querying your fan data directly from the API documentation.

Get API access — start building.

Full REST API for OnlyFans automation. Get started in minutes.

Get Access →

Ready to automate your OnlyFans operations?

Get full API access and start building in minutes.