Zum Hauptinhalt springen
tsecurity.de LIVE
Echtzeit-Radar & Feeds
Alle RSS Feeds
👥 Community & Social
Sichere ProgrammierungThe Indie Dev Visibility Playbook: From Zero Users to Your First 100(21.09.2026 um 00:08 Uhr)
Sichere ProgrammierungBase, Chat and Reasoning Models: How Are They Different?(21.09.2026 um 00:09 Uhr)
Sichere ProgrammierungHexfield Deck is for Kanban lovers and Markdown believers(21.09.2026 um 00:20 Uhr)
Sichere ProgrammierungPermissions and Authorisation: A Practical Playbook(21.09.2026 um 00:21 Uhr)
Linux Tipps & Hardeningfilet | Terminal File Manager(20.09.2026 um 21:03 Uhr)
Linux Tipps & HardeningLooking for feedback on my Linux Distro(20.09.2026 um 21:03 Uhr)
Sichere ProgrammierungThe Indie Dev Visibility Playbook: From Zero Users to Your First 100(21.09.2026 um 00:08 Uhr)
Sichere ProgrammierungBase, Chat and Reasoning Models: How Are They Different?(21.09.2026 um 00:09 Uhr)
Sichere ProgrammierungHexfield Deck is for Kanban lovers and Markdown believers(21.09.2026 um 00:20 Uhr)
Sichere ProgrammierungPermissions and Authorisation: A Practical Playbook(21.09.2026 um 00:21 Uhr)
Linux Tipps & Hardeningfilet | Terminal File Manager(20.09.2026 um 21:03 Uhr)
Linux Tipps & HardeningLooking for feedback on my Linux Distro(20.09.2026 um 21:03 Uhr)
Intelligence View
⚡ tsecurity.de Intelligence

How a Free Trial Without Upfront Card Killed Our SaaS Conversion Rate

Reagiere als Erste:r — dein Feedback zählt!

TL;DR

We had 11 free-trial users on a paid Colombian legaltech plan over 30 days. Trial→paid conversion: 0%. Spoiler: it wasn't a PMF problem. It was a billing-architecture bug.

If your trial doesn't tokenize a card upfront, your cron job has nothing to charge when the trial ends. The user silently downgrades to free, and your "trial conversion rate" is mathematically impossible.

Here's how we found it, and the .NET 10 + EF Core fix.

Context

I'm building NeoJurídico, a court-process monitoring platform for Colombian lawyers. The Litigante plan ships with a 14-day free trial activated via UTM-tagged Google Ads campaigns. Tech stack: .NET 10, EF Core 10, PostgreSQL, MercadoPago for billing, Angular 21 on the frontend.

The 0% trial→paid mystery

We were spending real money on Ads and getting 11 trials/month. Zero ever converted. So we audited the funnel:

Step Count
Ads → click 119/30d
Click → signup 8 (CTR 6.7%)
Signup → activated trial 11/30d (some pre-Ads)
First process created (Aha moment) 5/8 (62.5%)
Trial → paid 0

Activation looked healthy. Engagement existed. So why zero conversions?

Reading the SQL

SELECT us."Id", us."UserId", us."Status",
       us."MpPreapprovalId" IS NOT NULL AS has_card
FROM neo.user_subscriptions us
WHERE us."CampaignId" IS NOT NULL
ORDER BY us."CreatedAt" DESC LIMIT 11;
 Id  | UserId | Status | has_card
-----+--------+--------+----------
 146 |   3    | Open   | f
 145 |  44    | Open   | f
 144 |  43    | Open   | f
 ... (all 11 rows: has_card = f)

Zero of eleven trials had a payment method attached. That's the root cause.

Tracing the code

In our SubscriptionsService:

bool needsMpSubscription = isPaidPlan && !hasTrial && !hasCampaign;

If the user came in via campaign + trial, we skipped MercadoPago entirely. The trial activated as Status="Open" with TrialEndDate=now+15d, but with no preapproval ID.

Then the TrialExpirationHandler runs every 6 hours:

foreach (var userId in expiredCampaignSubscriptions) {
    await enrollmentService.RestoreOriginalSubscriptionIfNeededAsync(userId, ct);
}

"Restore" means "downgrade silently to the free plan." There's no path to charge — there was never a card.

We were running a free 15-day trial with structurally zero conversion potential.

The fix: card upfront, deferred first charge

MercadoPago's preapproval API supports start_date for deferring the first recurring charge:

// In SubscriptionsService.ActivateSubscriptionAsync
bool isTrialAwaitingCheckout = hasCampaign && hasTrial && isPaidPlan;
if (isTrialAwaitingCheckout) {
    status = "Pending";
    statusReason = "AwaitingTrialCheckout";
    trialEndDate = now.AddDays(trialDays!.Value);
}

Now signup creates a Pending subscription. The frontend (Angular) detects it on /app/dashboard and redirects:

if (response.entity.status === 'Pending'
    && response.entity.statusReason === 'AwaitingTrialCheckout') {
  this.router.navigate(['/app/suscripcion/checkout', planId],
                       { queryParams: { trial: 'true' } });
}

The user sees a checkout: "14 días gratis. No se cobra hoy. Primera carga: [date+14]." When they submit, we tokenize the card and create the MP preapproval with startDate = trialEndDate:

var preapprovalId = await _mpSubscriptionService.CreateAuthorizedSubscriptionAsync(
    plan.Name, plan.Price, user.Email, request.CardTokenId,
    backUrl, ct, externalReference: $"neo-sub-{sub.Id}",
    startDate: deferredStart  // = TrialEndDate
);

MP holds the card today, charges in 14 days. Trial→paid is now automatic instead of impossible.

For users who refuse to give a card, an explicit "skip to free plan (1 process limit)" button calls POST /skip-trial-to-free which closes the Pending and activates Plan Semilla. They self-segment.

The hidden lesson: zero conversions ≠ zero PMF

I almost made an expensive pivot decision based on the 0% number. The temptation was:

  • "Cut trials, force payments upfront on everyone"
  • "Limit free plan to 1 process to push conversion"
  • "Maybe the product isn't ready"

The data didn't support any of that. The bottleneck was a billing-flow architecture choice that made conversion mathematically impossible — not a value problem.

If you're seeing 0% on a critical funnel metric, before pivoting your business model, run this query against your billing data:

SELECT COUNT(*) FILTER (WHERE has_payment_method) AS chargeable,
       COUNT(*) AS total
FROM your_trial_subscriptions
WHERE created_at > NOW() - INTERVAL '30 days';

If chargeable / total is 0, you can't possibly convert anything. Fix that before changing anything else.

Server-side event tracking matters too

We also had GA4 emitting subscription_activated from the frontend card-checkout component. But trials never reached that component (no card flow). So GA4 showed 0 activations while our DB showed 11.

Solution: server-side GA4 via Measurement Protocol when status transitions to Open in the SubscriptionsService. Now event tracking matches reality regardless of which path the user takes.

if (_ga4 != null && s.Status == "Open" && hasCampaign && hasTrial) {
    var expectedValue = Math.Round(plan.Price * 0.36m, 0);
    await _ga4.TrackTrialStartedAsync(
        userId, plan.Name, expectedValue, "COP", trialDays.Value, ct);
}

(Using expected_value = MRR × 0.36 as the proxy for Smart Bidding. Trials aren't revenue — don't pass nominal price as conversion value or Google will optimize for trials, not paying customers.)

Takeaways

  1. If trial lifecycle doesn't include "tokenize a payment method," you have zero ability to convert. No amount of UX or pricing changes fixes architecture.
  2. Validate metric anomalies (0% conversion) by reading your DB schema, not by changing pricing.
  3. Server-side analytics for revenue events is non-negotiable. Frontend gtag dies in 30% of sessions due to ad-blockers.
  4. Self-segment users at the checkout: "card or downgrade to free." Don't force, don't trick — let them choose, then measure.

The plumbing is now in production. We'll see the trial→paid conversion rate on the next cohort. I'll write a follow-up in 30 days with real numbers.

I work on NeoJurídico, a court-process monitoring platform for Colombian lawyers. Always interested in connecting with other LATAM SaaS founders or LegalTech builders. Reach out if your country has equally cursed government APIs.

Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten How a Free Trial Without Upfront Card Killed Our SaaS Conversion Rate

Thematisch verwandte Begriffe: Free, Trial, Without, Upfront · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Zum Aktualisieren ziehen
ZERO-DAY CVE-2026-93957 | A vulnerability has been found in olivier-ls PHP-FTS up to 1.1.3. This a…
Advisory →
TTS Reader • tsecurity.de Voice
tsecurity.de Icon
tsecurity.de App
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag
Themen-Radar & Intelligence Matrix
Echtzeit-Taxonomie nach Angriffsvektoren & Plattformen

tsecurity.de Live Threat Radar

🔴 LIVE RADAR
MONITORING
AKTIV
CVE-DATENBANK
LIVE
🔍
Community Radar & Live Chat
Sentinel Bot online • Live-Stream
Dein Cluster: Security Explorer
Match:
lädt…
Verbindung zum Community-Stream wird aufgebaut...
Bearbeitungsmodus — Senden überschreibt deine Nachricht
Community-Puls — was gerade passiert
lädt…
Aktivitäten deiner Analysten
lädt…
Neues Thema oder Eilmeldung einreichen

Reiche interessante Links, Zero-Days oder Debatten ein. Die Community entscheidet per Upvote über die Veröffentlichung.

Heiß diskutierte Einreichungen
🔖 Gespeicherte Artikel
📂 Keine gespeicherten Artikel vorhanden.
Zurück Ziehen Vor
Links: vorheriger Artikel Rechts: nächster Artikel unten: schließen
News NIS-2 Frühwarnung Tier-1 Intel ⏱️ 3 Min vor 10 Min
Artikeldaten werden geladen...

Zurück: vorheriger Vor: nächster
↗ Original-Quelle
Social Reaktionen Deine Reaktion zählt
Einstufung & Relevanz-Poll 0 Stimmen
In sozialen Netzwerken teilen 1-Klick