diff --git a/.env.example b/.env.example index 5d0d2f2..2f7d1d8 100644 --- a/.env.example +++ b/.env.example @@ -38,6 +38,10 @@ OPENFRAME_REQUIRE_INVITE_CODE="true" # default: the rows only pay for themselves if you are running a signup funnel. # Everything is written to this instance's own database and sent nowhere. OPENFRAME_ENABLE_ANALYTICS="false" +# The date the cardless trial replaced the card-first one, as an ISO date. Set it +# to have /admin/growth compare signup-to-paid either side of the switchover; +# leave it empty and that section is simply not shown. +OPENFRAME_CARDLESS_TRIAL_LAUNCHED_AT="" SELF_HOSTED_AUTO_CREATE_BUCKET="false" # ============================================================================ diff --git a/README.md b/README.md index 79f6dfd..2e6eadc 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ OpenFrame is a fair source video review and approval platform for teams that need clear feedback, version control, and client-friendly review links in one place. It supports collaborative review workflows out of the box and can be self-hosted with the Docker setup included in this repository. -Prefer not to self-host? You can try OpenFrame at [open-frame.net](https://open-frame.net) with a 7-day free trial, then continue on the hosted plan starting at $10. +Prefer not to self-host? You can try OpenFrame at [open-frame.net](https://open-frame.net) with a 7-day free trial that needs no card, then continue on the hosted plan starting at $10. ## Product Screenshot diff --git a/app/(dashboard)/layout.tsx b/app/(dashboard)/layout.tsx index b186a81..23e7de7 100644 --- a/app/(dashboard)/layout.tsx +++ b/app/(dashboard)/layout.tsx @@ -1,16 +1,20 @@ -import { Header } from '@/components/layout'; +import { Header, TrialBanner } from '@/components/layout'; import { auth } from '@/lib/auth'; import { hasAppNavigationAccess } from '@/lib/route-access'; +import { getTrialNotice } from '@/lib/billing'; export default async function DashboardLayout({ children }: { children: React.ReactNode }) { const session = await auth(); - const showAppNavigation = session?.user?.id - ? await hasAppNavigationAccess(session.user.id) - : false; + const userId = session?.user?.id; + const [showAppNavigation, trialNotice] = await Promise.all([ + userId ? hasAppNavigationAccess(userId) : false, + userId ? getTrialNotice(userId) : null, + ]); return (
Start your 7-day free trial
++ Your free trial runs until{' '} + {new Date(billing.subscription.trialEndsAt).toLocaleDateString()} +
- Get full access to all features — no charge until the trial ends. Cancel - anytime. + Every feature is on and no card is on file. The trial covers one workspace and + one project. Subscribing starts your paid month straight away, so there is no + reason to do it before you are ready.
- Stored media cleanup is scheduled after{' '} - {new Date(billing.subscription.storageCleanupEligibleAt).toLocaleDateString()}{' '} - unless billing is restored first. + Nothing has been deleted. Your projects and media are kept until{' '} + {new Date(billing.subscription.storageCleanupEligibleAt).toLocaleDateString()}; + subscribe before then and everything is where you left it.
) : null} @@ -479,8 +482,6 @@ export default function SettingsPage({ billingOnly = false }: { billingOnly?: bo+ Accounts created in the {scoreboard.cohorts.windowDays} days either side of{' '} + {formatDate(scoreboard.cohorts.cutover)}, each given{' '} + {scoreboard.cohorts.observationDays} days from signup to convert. The rate to read is + signup to paid: dropping the card requirement multiplies trials, so trial to paid can + fall while more people pay. +
+| Cohort | +Window | +Signup | +Trial | +Paid | +Signup to paid | +Trial to paid | +
|---|---|---|---|---|---|---|
| + {row.cohort === 'CARDLESS' ? 'cardless' : 'card first'} + | ++ {formatDate(row.windowStart)} to {formatDate(row.windowEnd)} + | +{row.signups} | +{row.trials} | +{row.paid} | +
+ |
+
+ |
+
+ Nothing to compare yet. The first cardless signups reach the end of their{' '} + {scoreboard.cohorts.observationDays}-day window {scoreboard.cohorts.observationDays}{' '} + days after the switchover. +
+ ) : null} +All new accounts are eligible for a{' '} 7-day free trial with full access to paid - features. We strongly encourage you to evaluate the Service fully during this period - before subscribing. + features. The trial requires no credit card and collects no payment. We strongly + encourage you to evaluate the Service fully during this period before subscribing.
- You may cancel at any time during your free trial without being charged. If you do not - cancel before the trial ends, your chosen plan will automatically activate and payment - will be collected. + The trial never activates a paid plan by itself. When it ends, paid features stop + until you choose to subscribe, and a subscription is charged as soon as you complete + checkout.
diff --git a/app/terms/page.tsx b/app/terms/page.tsx index 4d6f50e..937570d 100644 --- a/app/terms/page.tsx +++ b/app/terms/page.tsx @@ -58,7 +58,7 @@ export default function TermsOfServicePage() { OpenFrame is a video review and approval platform that enables creative professionals and their clients to collaborate on video projects through timestamped comments, annotations, version management, and approval workflows. The Service is offered on a - subscription basis with a free trial period. + subscription basis with a free trial period that requires no payment details. @@ -96,11 +96,12 @@ export default function TermsOfServicePage() { 5. Subscriptions and Free Trial- Certain features of the Service require a paid subscription. We offer a{' '} - 7-day free trial for new accounts, during - which you may access paid features at no charge. At the end of the trial period, your - subscription will automatically convert to a paid plan unless you cancel before the - trial ends. + Certain features of the Service require a paid subscription. Every new account + receives a 7-day free trial, which starts + once the account's email address is verified and requires no credit card. The + trial does not convert into a paid plan on its own and nothing is charged while it + runs. When it ends, access to paid features stops until you choose to subscribe, and a + subscription is billed as soon as you complete checkout.
Subscription fees are billed in advance on a monthly or annual basis depending on the
diff --git a/components/LandingPage.tsx b/components/LandingPage.tsx
index 4a0cb6d..a99c3ef 100644
--- a/components/LandingPage.tsx
+++ b/components/LandingPage.tsx
@@ -263,12 +263,12 @@ export function LandingPage({ isLoggedIn }: LandingPageProps) {
href={hostedCtaHref}
className="group relative isolate inline-flex h-12 min-w-max items-center justify-center overflow-hidden border border-primary bg-primary px-10 text-sm font-medium whitespace-nowrap text-primary-foreground transition-transform duration-300 hover:scale-[1.02]"
>
- Start free trial
+ Start 7-day free trial, no card required
- 7-day free trial · Flat $10/mo — no per-seat fees · No client accounts + No credit card · Flat $10/mo after, no per-seat fees · No client accounts
/ month- Starts with a 7-day free trial. Cancel anytime. + Starts with a 7-day free trial. No credit card. Cancel anytime.
- OpenFrame is $10/month flat with a 7-day free trial. You do not pay per team member, - collaborator, or guest reviewer. Self-hosting is free with Docker. + OpenFrame is $10/month flat with a 7-day free trial that never asks for a card. You + do not pay per team member, collaborator, or guest reviewer. Self-hosting is free + with Docker.