I launched a registration wall on the Miami Beach Journal -- read three free articles, then create a free account to continue. The wall was live for weeks. Traffic was steady. But registrations were at zero.

The Data

I checked production logs for registration errors. Nothing -- no failed attempts, no 500s. Then I looked at the paywall analytics:

  • 167 paywall impressions -- people were hitting the wall
  • 0 register button clicks
  • 0 sign-in clicks

Zero clicks on 167 impressions. That's not a registration bug. That's a conversion problem.

The Tracking Was Also Broken

Or was it? Click tracking used fetch() to record button clicks. But the "Create Free Account" button was an <a> linking to /register. The browser navigated immediately, killing the fetch request before it completed.

// BEFORE -- fetch() gets killed on navigation
function trackPaywallEvent(eventType) {
    fetch('/api/paywall-event', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ event_type: eventType, article_id: articleId }),
    });
}

// AFTER -- sendBeacon survives page navigation
function trackPaywallEvent(eventType) {
    var data = JSON.stringify({
        event_type: eventType,
        article_id: articleId ? parseInt(articleId) : null,
    });
    if (eventType !== 'impression' && navigator.sendBeacon) {
        navigator.sendBeacon('/api/paywall-event',
            new Blob([data], { type: 'application/json' }));
    } else {
        fetch('/api/paywall-event', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: data,
            keepalive: true,
        });
    }
}

Just because analytics show zero doesn't mean zero happened. Broken tracking can mask real user behavior.

What the Pros Do

I studied NYT, Washington Post, WSJ, and The Athletic. The pattern was consistent: they never redirect you away from the article. The text fades out, a registration form appears right there as a modal overlay. You fill it out, the article appears. You never lose your place.

My implementation redirected to a separate /register page. The reader loses context, adds a page load, and psychologically feels like giving up on the article. The article behind the wall is the motivation -- remove it from view and you remove the motivation to register.

What I Rebuilt

Inline modal registration. Clicking "Create Free Account" now opens a form as a modal overlay on the article page. Submits via AJAX, reloads to show the full article. The reader never leaves.

Verify later. Instead of requiring email verification before access, I grant access immediately. A small dismissible banner reminds them to verify. Verification is only enforced for sensitive actions. The moment someone registers is the moment they're most engaged -- don't send them away to check their inbox.

The entire change was about 300 lines across 8 files, zero database changes.