Case Study 7 min read

We Shifted Posting Times by 6 Hours and Revenue Jumped 22%

We were posting at 2PM EST based on gut feel. One API call revealed 40% of our top creator's audience was asleep during that window. Three weeks after fixing it, revenue was up 22%.

OFAPI Team ·

We had a posting schedule that felt solid. 2PM EST every day — peak US afternoon, people on their lunch breaks, that general wisdom you hear repeated in every OnlyFans creator forum. We had been posting at 2PM for eight months across our whole roster.

We had no data to support it. We’d just read it somewhere and never questioned it.

When we finally pulled geographic audience data through the API for our top creator — a creator doing $47,000 a month — the numbers were uncomfortable. 40% of her paying subscribers were based in Europe and Australia. At 2PM EST, it was 8PM in London and 4AM in Sydney. Half her audience was either winding down for the night or genuinely asleep when her content dropped.

She was doing $47K a month posting into a timezone void. We shifted her schedule. Three weeks later, revenue was up 22%.

This is the full story of what we found, what we changed, and how to run the same analysis on your own creators.

The Assumption We Never Questioned

Most onlyfans content scheduling advice is written from a US-centric perspective. Post at 2PM EST. Post at 7PM EST. Post when Americans are active. That advice is fine if your audience is predominantly American.

A surprising number of creators — especially those with significant social media followings, international promotional presence, or content in languages other than English — have audience distributions that look nothing like this assumption.

We didn’t know because we never looked.

OnlyFans’ native analytics show some geographic data, but it’s aggregated and buried. There’s no easy way to see: what percentage of my revenue is coming from which timezone, and when are those fans actually online?

The API changes this. The /stats/reach/by-country endpoint returns subscriber and revenue breakdown by country. From there, it’s a matter of mapping countries to timezones and identifying when your paying audience is actually awake.

The Data Pull

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

API_BASE = "http://157.180.79.226:4024/api/v1"
HEADERS = {"X-API-Key": "YOUR_API_KEY"}

# Map major subscriber countries to primary timezone offset (UTC)
COUNTRY_TIMEZONE_MAP = {
    "US": "America/New_York",
    "GB": "Europe/London",
    "DE": "Europe/Berlin",
    "FR": "Europe/Paris",
    "AU": "Australia/Sydney",
    "CA": "America/Toronto",
    "NL": "Europe/Amsterdam",
    "SE": "Europe/Stockholm",
    "NO": "Europe/Oslo",
    "JP": "Asia/Tokyo",
    "KR": "Asia/Seoul",
    "BR": "America/Sao_Paulo",
    "MX": "America/Mexico_City",
    "NZ": "Pacific/Auckland",
    "IT": "Europe/Rome",
    "ES": "Europe/Madrid",
}

def analyze_audience_timezones(creator_id: str):
    """
    Pull geographic reach data and identify when the paying audience is online.
    Returns a breakdown of subscriber/revenue share by timezone cluster.
    """
    resp = requests.get(
        f"{API_BASE}/stats/reach/by-country",
        headers=HEADERS,
        params={"creator_id": creator_id}
    )
    country_data = resp.json()["countries"]

    total_revenue = sum(c["revenue"] for c in country_data)
    total_subs = sum(c["subscribers"] for c in country_data)

    timezone_clusters = defaultdict(lambda: {
        "revenue": 0.0,
        "subscribers": 0,
        "countries": [],
        "timezone": None
    })

    for country in country_data:
        code = country["country_code"]
        tz_name = COUNTRY_TIMEZONE_MAP.get(code, "UTC")

        timezone_clusters[tz_name]["revenue"] += country["revenue"]
        timezone_clusters[tz_name]["subscribers"] += country["subscribers"]
        timezone_clusters[tz_name]["countries"].append(code)
        timezone_clusters[tz_name]["timezone"] = tz_name

    results = []
    for tz_name, data in timezone_clusters.items():
        tz = pytz.timezone(tz_name)
        now_local = datetime.now(tz)

        results.append({
            "timezone": tz_name,
            "countries": data["countries"],
            "revenue_share": round(data["revenue"] / total_revenue * 100, 1),
            "subscriber_share": round(data["subscribers"] / total_subs * 100, 1),
            "raw_revenue": round(data["revenue"], 2),
            "subscribers": data["subscribers"],
            "current_local_hour": now_local.hour
        })

    return sorted(results, key=lambda x: x["revenue_share"], reverse=True)


def find_optimal_post_times(timezone_data: list, target_local_hour_range=(18, 22)):
    """
    Given timezone clusters and a target local evening window (6PM-10PM local),
    find UTC post times that maximize audience reach during peak hours.
    """
    recommendations = []

    for cluster in timezone_data:
        if cluster["revenue_share"] < 5:
            continue  # Skip clusters under 5% revenue share

        tz = pytz.timezone(cluster["timezone"])
        # Find the UTC time that corresponds to 8PM local for this cluster
        today = datetime.now(tz).date()
        local_8pm = tz.localize(datetime(today.year, today.month, today.day, 20, 0))
        utc_8pm = local_8pm.astimezone(pytz.utc)

        recommendations.append({
            "timezone": cluster["timezone"],
            "revenue_share": cluster["revenue_share"],
            "post_at_utc": utc_8pm.strftime("%H:%M UTC"),
            "post_at_est": local_8pm.astimezone(
                pytz.timezone("America/New_York")
            ).strftime("%I:%M %p EST")
        })

    return recommendations


# Run the analysis
audience_data = analyze_audience_timezones("creator_abc123")
optimal_times = find_optimal_post_times(audience_data)

print("=== Audience Timezone Distribution ===")
for cluster in audience_data:
    print(f"{cluster['timezone']}: {cluster['revenue_share']}% of revenue, "
          f"{cluster['subscriber_share']}% of subs")

print("\n=== Recommended Post Times ===")
for rec in optimal_times:
    print(f"For {rec['timezone']} audience ({rec['revenue_share']}% of revenue): "
          f"Post at {rec['post_at_est']} ({rec['post_at_utc']})")

What We Found for Our Top Creator

Running this on our $47K/month creator produced a clear picture:

Timezone ClusterRevenue ShareSubscriber Share
America/New_York38%41%
Europe/London + Europe/Berlin27%24%
Australia/Sydney + NZ13%11%
Other22%24%

Nearly 40% of her revenue — roughly $18,800/month — was coming from fans who were either asleep or heading to bed when she posted at 2PM EST.

The script told us the optimal post times to hit each major cluster during their evening peak:

  • 8AM EST — captures European evening (8PM London, 9PM Berlin)
  • 6PM EST — captures Australian morning (8AM Sydney)
  • 8PM EST — captures US evening (existing audience, underserved)

We had been posting once a day at 2PM. We moved to three posts: 8AM, 6PM, and 8PM EST — with the primary content drop at 8AM to lead with the European window.

The Three-Week Result

We ran the new schedule for 21 days without any other changes — same content quality, same volume, same promotional spend.

  • Revenue: Up 22% ($47,000 → $57,340 annualized run rate)
  • Session duration: Up 35% — fans were online when content dropped, so engagement windows extended
  • PPV open rate: Up 18% — mass PPV pushes now hit inboxes when fans are actually active
  • New subscriber conversion: Up 11% — profile visits converted better because fans arrived to fresh content

The session duration stat was the one that surprised us most. When you post at 2PM EST and a British fan sees it at 9PM their time, they’re online, engaged, and have time to browse. Compare that to posting at 2PM and having them see it at 7AM the next morning, when they’re rushing to work. Same content, completely different context.

How We Applied This Across the Roster

After proving it on one creator, we ran the timezone analysis across all 12 creators on our roster. The findings varied:

  • 6 creators had primarily US-based audiences. Their existing 2PM/7PM schedule was actually reasonable. We made minor adjustments.
  • 4 creators had significant European or Australian audiences (25%+ of revenue) that were being posted into dead hours. We rescheduled all four.
  • 2 creators had Japanese and Korean audiences that none of our existing posts were reaching at all. We added early-morning EST posts specifically for that window.

Across the full roster, the average revenue lift from schedule optimization was 14% — with the biggest gains on the creators with the most misaligned schedules.

The Operational Change

Running three posts per day instead of one felt overwhelming before we built the scheduling system. In practice, it meant batching content creation (same as before) and just distributing the posts across the day automatically.

We now use the content analytics use case to track engagement by post time, which lets us refine the schedule further each month as our creators’ audience compositions shift.

The integrations page has details on connecting the scheduling workflow to the tools your team already uses.


The best time to post on OnlyFans is when your actual audience is awake and online. That answer is different for every creator. Your audience geographic data is sitting in the API right now — the analysis takes about 20 minutes to run.

Check the pricing page to get started, or go straight to the getting started guide to make your first call.

Your 2PM post might be someone’s 4AM. Check the data.

Ready to automate your OnlyFans operations?

Get full API access and start building in minutes.