Data Analysis 10 min read

We Pulled Fan Stats and Discovered 60% of Churn Happens in Week 2

An agency pulling 200 new subscribers a month was barely growing. When we ran the numbers through the fan stats endpoint, we found the problem — and it was hiding in week two.

OFAPI Team ·

For three months straight, our team celebrated the same milestone: 200 new subscribers per month across one of our mid-tier creators. The creator was thrilled. The team was optimistic. Then we pulled the actual net growth numbers.

Twenty. We were adding twenty net subscribers a month.

We were pouring time and ad spend into acquiring 200 fans and keeping 10% of them. The other 180 were walking out a door we didn’t even know was open. When we finally ran the data through the /stats/fans endpoint, what we found reshaped how we think about onlyfans subscriber retention entirely.

The Moment We Realized We Had a Churn Problem

The surface-level metric — new subscribers — felt good because it was moving. But new subscribers are a vanity metric if your onlyfans churn rate is eating them alive. We weren’t tracking expirations carefully, we weren’t correlating cancellation timing with any fan behavior, and we had no early warning system.

When we started building one, the first thing we needed was granular fan data. The /stats/fans endpoint gave us subscriber join dates, subscription status, and activity history. Combined with /fans/info for individual fan records, we could reconstruct the exact timing of every cancellation over a 90-day window.

import requests
from datetime import datetime, timedelta
from collections import defaultdict

API_KEY = "your_api_key"
BASE_URL = "http://157.180.79.226:4024/api/v1"

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

def get_fan_stats(creator_id):
    response = requests.get(
        f"{BASE_URL}/stats/fans",
        headers=headers,
        params={"creator_id": creator_id, "limit": 1000}
    )
    response.raise_for_status()
    return response.json()

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

def build_churn_timeline(creator_id):
    stats = get_fan_stats(creator_id)
    fans = stats.get("fans", [])

    # Bucket churned fans by days-since-join at time of cancellation
    churn_by_day = defaultdict(int)
    total_churned = 0

    for fan in fans:
        if fan.get("subscriptionStatus") == "expired":
            joined = datetime.fromisoformat(fan["joinDate"])
            cancelled = datetime.fromisoformat(fan["expirationDate"])
            days_active = (cancelled - joined).days
            if days_active <= 30:
                churn_by_day[days_active] += 1
                total_churned += 1

    return churn_by_day, total_churned

churn_timeline, total = build_churn_timeline("creator_123")

# Print distribution
week1 = sum(v for k, v in churn_timeline.items() if k <= 7)
week2 = sum(v for k, v in churn_timeline.items() if 8 <= k <= 14)
week3_4 = sum(v for k, v in churn_timeline.items() if k > 14)

print(f"Total early churn (30 days): {total}")
print(f"Week 1 churn: {week1} ({week1/total*100:.1f}%)")
print(f"Week 2 churn: {week2} ({week2/total*100:.1f}%)")
print(f"Week 3-4 churn: {week3_4} ({week3_4/total*100:.1f}%)")

The output stopped us cold.

Week 1 churn: 18% Week 2 churn: 60% Week 3-4 churn: 22%

We ran it again. Same numbers. Sixty percent of all early cancellations were happening in days 8 through 14. Not in week one when fans are still deciding. Not in weeks three or four when they’ve made a real commitment. Week two. The honeymoon period that we had completely ignored.

Why Week Two Is the Danger Zone

When we dug into the fan behavior data through /chats, the pattern became clear. Week one fans are engaged — they subscribed, they’re poking around, they’re opening the welcome DM (if there even was one). The creator’s content is new to them.

By week two, the novelty has worn off. If no one has reached back out, if there’s been no personal touchpoint, if the fan feels like one of thousands rather than a valued subscriber — they cancel. The subscription auto-renews in two weeks, and fans who feel like strangers don’t renew.

We were losing fans in the exact window where a single personal touchpoint would have changed the outcome.

The worst part: these weren’t low-value fans. When we cross-referenced churn timing with spend data, week-two churners had average initial spend that was 34% higher than fans who survived past day 30. The fans most willing to spend were the ones we were losing fastest.

Building the 14-Day Onboarding Sequence

We designed a four-touchpoint sequence built around the critical window we’d identified. Every new subscriber now enters an automated onboarding track:

Day 1 — Welcome DM. Sent automatically within 2 hours of subscription. Personalized with the subscriber’s username. Not a generic “thanks for subscribing” — something that signals the creator actually noticed them.

Day 3 — Exclusive content drop. A piece of content that doesn’t appear on the main feed. Framed as insider access. Makes the fan feel like the subscription is already paying off beyond the public content they could have seen.

Day 7 — Personalized check-in. A DM from the creator (written in the creator’s voice, sent by the chatter team) asking what kind of content they want more of. This is the data-collection touchpoint — the responses also inform content strategy. More importantly, it makes the fan feel seen.

Day 12 — Renewal anchor. Two days before the natural renewal window, the fan receives a “loyal subscriber” message with either a bonus piece of content or a PPV offer at a price point slightly below their observed spend history. This primes them to see value right before the renewal decision.

We built the trigger logic on top of /chats — monitoring when new subscriptions came in and scheduling messages through the API at the appropriate day offsets.

import requests
from datetime import datetime, timedelta

API_KEY = "your_api_key"
BASE_URL = "http://157.180.79.226:4024/api/v1"

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

ONBOARDING_SEQUENCE = [
    {"day": 1,  "message": "Hey {username} — welcome. Genuinely glad you're here. I post a lot that doesn't make it to the main page, so stay close. Anything specific you want to see more of?"},
    {"day": 3,  "message": "Made something just for subscribers this week — dropping it now. Hope you like it."},
    {"day": 7,  "message": "Hey {username} — one week in. Curious what you've been enjoying most? I want to make more of what you actually want."},
    {"day": 12, "message": "You've been here almost two weeks and I appreciate it. I put together something exclusive for people who stick around — sending it your way."},
]

def schedule_onboarding(fan_id, username, join_date_str, creator_id):
    join_date = datetime.fromisoformat(join_date_str)

    for step in ONBOARDING_SEQUENCE:
        send_at = join_date + timedelta(days=step["day"])
        message = step["message"].format(username=username)

        payload = {
            "creator_id": creator_id,
            "fan_id": fan_id,
            "message": message,
            "scheduledAt": send_at.isoformat()
        }

        response = requests.post(
            f"{BASE_URL}/chats",
            headers=headers,
            json=payload
        )

        if response.status_code == 201:
            print(f"Scheduled day-{step['day']} message for {username} at {send_at.date()}")
        else:
            print(f"Failed to schedule day-{step['day']}: {response.text}")

# Example: schedule onboarding for a new subscriber
schedule_onboarding(
    fan_id="fan_456",
    username="JohnDoe99",
    join_date_str="2026-03-05T14:23:00",
    creator_id="creator_123"
)

The Before and After

We ran the sequence for 60 days before pulling comparison numbers. The methodology wasn’t perfect — we weren’t running a controlled experiment — but the directional results were significant enough to act on.

Before the sequence:

  • Month 1 net subscriber growth: +22
  • 30-day retention rate: 11%
  • Week 2 churn as a share of total early churn: 60%

After the sequence (60-day average):

  • Month 1 net subscriber growth: +89
  • 30-day retention rate: 44%
  • Week 2 churn as a share of total early churn: 31%

The week-two churn didn’t disappear — but it dropped from 60% of early losses to 31%. Combined with modest improvements in weeks 3-4, net subscriber growth went from 11% of acquisition to 44%. On 200 new subscribers per month, that’s the difference between +22 net and +89 net. At the creator’s average monthly revenue per subscriber, that gap translated to roughly $4,200/month in recovered subscription revenue.

What surprised us most was the day-7 response rate. More than half of the fans who received the “what do you want to see?” message actually replied. That data fed directly back into content planning. The onboarding sequence became a research channel as much as a retention tool.

What the Data Actually Changes

The insight here isn’t that week two is important — it’s that you can’t know when the critical window is without pulling your own data. Every creator’s churn curve is different. Some creators see the biggest drop-off in week one. Some see it at the 30-day renewal. Without running the analysis, you’re applying generic retention advice to a specific situation that may look nothing like the general case.

The /stats/fans endpoint gives you the raw material to find your own critical window. Once you know when fans are most likely to leave, you can concentrate your retention effort there instead of spreading it evenly across the subscriber lifecycle.

For more on building automated retention sequences, see our churn prediction use case and the Slack integration guide for setting up real-time alerts when new subscribers enter their at-risk window.


If you are not yet pulling fan-level data and you are managing more than one or two creators, you are almost certainly missing the same pattern we were. The data is available — it is just a matter of pulling it.

See what the OFAPI dashboard can surface about your creator portfolio, or start making calls directly from the API documentation.

Ready to automate your OnlyFans operations?

Get full API access and start building in minutes.