5 min read

Free to Paid Conversion Rates

Updated February 3, 2021

In this analysis we’ll try to estimate the proportion of Free users that convert to a paid plan in Publish.

Key Findings

Around 1000-1500 conversion events happen each month without a trial starting in the preceding 30 days. This represents around 35% of all conversion events each month.

The free-to-paid conversion rate was estimated by looking at the number of Subscription Started events that came from users without an associated trial and dividing it by the total number of users that signed up that month less the number that converted with a trial.

With the deprecation of Buffer Classic, which was perhaps the main source of users subscribing without a trial, the estimated proportion of users that purchase a paid subscription after having been on a Free plan for multiple weeks is around 0.85% to 1%.

The conversion rate may seem lower in recent months and appear to show a negative trend, but this doesn’t necessarily suggest that a lower proportion of free users are converting to paid plans. Instead I believe this is an effect of users taking a significant amount of time to convert.

For example, people that signed up in January 2020 will have had 13 full months to subscribe to a paid plan, whereas those that signed up in December 2020 will only have had a couple months.

# connect to bigquery
con <- dbConnect(
  bigrquery::bigquery(),
  project = "buffer-data"
)

# to make bigquery work
options(scipen = 20)

# define sql query
sql <- "
  select distinct
    u.id as user_id
    , u.account_id
    , u.created_at as signup_at
    , ps.client_name
    , ps.signup_with_trial
    , ps.source
    , t.id as trial_id
    , t.timestamp as trial_start_at
    , s.id as sub_start_id
    , s.original_timestamp as converted_at
    , s.plan_id
    , s.subscription_id
    , s.trial_start_date as sub_trial_start
    , s.trial_end_date as sub_trial_end
  from dbt_buffer.publish_users u
  left join dbt_buffer.segment_product_signups ps
    on ps.user_id = u.account_id
    and ps.product = 'publish'
  left join segment_publish_server.subscription_started s
    on s.user_id = u.account_id
  left join segment_publish_server.trial_started t
    on s.user_id = t.user_id
    and t.timestamp <= s.timestamp
  where u.created_at >= '2020-01-01'
"
  
# query BQ
users <- dbGetQuery(con, sql, page_size = 25000)

# save data
saveRDS(users, "free_to_paid_conversion.rds")

There are around 952 thousand users that have signed up since January 1, 2020.

Diagnostic Plots

Let’s plot the number of events that occur over time to spot check the data.

Let’s view signups by source.

We started putting all new signups on trials around August 2019. Next let’s view subscription starts.

The number of users starting subscriptions each weeks seems to have been increasing since the low point at the beginning of the Covid-19 pandemic. Next we’ll segment this chart by whether the user had a trial within 30 days of subscribing.

This plot seems to indicate that most Subscription Started events have a trial associated with them. Still, there seem to be a significant number of conversions that come from users that did not have a trial in the 30 days prior.

Around 25% of conversion events come from users that hadn’t had a trial or started one more than 30 days prior to the conversion event.

For those without trials, where did they sign up?

Most signed up from the client bufferWeb.

Conversion Rates

Next we will come up with a conversion rate for Free -> Paid. If the conversion event occurrs more than 30 days after the trial started (~16 days after the trial ends), we’ll assume that the user was on the Free plan for a sufficient amount of time.

What should the denominator be? We want the total number of users that were on the Free plan.

The conversion rate may seem lower in recent months and appear to show a negative trend, but this doesn’t necessarily suggest that a lower proportion of free users are converting to paid plans. Instead I believe this is an effect of users taking a significant amount of time to convert.

For example, people that signed up in January 2020 will have had 13 full months to subscribe to a paid plan, whereas those that signed up in December 2020 will only have had a couple months.

We can try to control for this by only looking at users that convert within X days of signing up, but this potentially excludes a significant number of subscribers. We see below that the proportion of users that convert within 30 days of signing up does not show a negative trend.

Now let’s look at the proportion of signups that converted within 30 days without a preceding trial.

Total Number of Conversions

Now let’s try to find the total number of users that convert to a paid plan without a trial in the previous 30 days.

# connect to bigquery
con <- dbConnect(
  bigrquery::bigquery(),
  project = "buffer-data"
)

# to make bigquery work
options(scipen = 20)

# define sql query
sql <- "
  select distinct
    t.id as trial_id
    , t.timestamp as trial_start_at
    , t.trial_end_date as trial_end_at
    , s.id as sub_start_id
    , s.timestamp as converted_at
    , s.plan_id
    , s.subscription_id
    , s.trial_start_date as sub_trial_start
    , s.trial_end_date as sub_trial_end
    , s.user_id
  from segment_publish_server.subscription_started s
  left join segment_publish_server.trial_started t
    on s.user_id = t.user_id
    and t.timestamp <= s.timestamp
    and timestamp_diff(s.timestamp, t.timestamp, day) <= 30
  where s.timestamp >= '2020-01-01'
"
  
# query BQ
conversions <- dbGetQuery(con, sql, page_size = 25000)

# save data
saveRDS(conversions, "subscription_started_events.rds")

Around 1000-1500 conversion events happen each month in which there isn’t a trial in the preceding 30 days. Consistently this represents around 35% of conversion events each month.