Author: onetwothreeadmin

  • AI prompt libraries don’t scale past twenty prompts

    AI prompt libraries don’t scale past twenty prompts

    If you’ve been using AI tools for more than three months, you probably have a growing collection of prompts saved somewhere. A Notion database. A Google Doc. Maybe a folder of text files with names like newsletter-intro-v3-final.txt.

    The problem isn’t saving prompts. The problem is finding the right one when you need it—and knowing whether the version you saved six weeks ago is still the best approach.

    Most prompt libraries fail around the twenty-prompt mark. Here’s why, and what actually works when you’re running a content business that depends on consistent AI output.

    The retrieval problem nobody talks about

    Prompts aren’t like recipes. You don’t browse them. You need them in context, under pressure, often mid-workflow.

    A Notion database works great when you have five prompts and remember what each one does. At twenty, you’re scanning titles. At forty, you’re using Notion’s search and hoping you tagged it correctly. At sixty, you’ve forgotten half of them exist.

    The failure mode isn’t storage—it’s retrieval. You need the prompt that generates product comparison tables, but you can’t remember if you called it “compare-products” or “product-table-builder” or “comparison-prompt-v2”. So you either waste five minutes searching or you write a new one from scratch, which defeats the purpose of saving prompts in the first place.

    Text files are worse. Folder hierarchies help until you need a prompt that could live in two categories. Do you file “write a cold-email follow-up” under Email or Sales or Outreach? You’ll forget. Six months later, you’ll create a duplicate.

    What works: context-based systems, not archives

    The operators I know who’ve solved this use one of three approaches, depending on how they work.

    Custom instructions in the AI tool itself. Both ChatGPT and Claude let you set default instructions that apply to every conversation. If 80% of your prompts share the same voice, format, or constraints—”always write in second person,” “keep paragraphs under three sentences,” “never use exclamation marks”—bake that into the tool. You’ll still need specific prompts for specific tasks, but you’ve eliminated the repetitive setup.

    Claude‘s Projects feature takes this further. You can create a project for, say, newsletter writing, upload your style guide and past issues, and set project-level instructions. Every conversation in that project starts with that context loaded. You’re not hunting for the right prompt—you’re working in the right environment.

    Snippet expansion tools. If you’re using prompts across multiple AI tools—ChatGPT for brainstorming, Claude for drafting, Perplexity for research—a snippet manager like TextExpander or Espanso beats a Notion database. Type a short trigger (;newsletter-intro) and it pastes the full prompt, wherever you are. No context switching. No hunting.

    The catch: snippet tools don’t handle nested prompts or conditional logic well. If your prompt has variables or depends on prior output, you’ll need something more structured.

    A single, linear prompt doc. This sounds too simple to work, but I’ve seen it succeed with operators who run high-volume content operations. One Google Doc. Chronological. Every new prompt gets added to the top with a date and a two-line description of what it does and when you used it. No folders. No tags. Just Cmd+F and a date range.

    The advantage: you don’t have to predict future search terms. You search for the outcome (comparison table) or the date you remember using it (April), and it surfaces. The disadvantage: it only works if you actually write those two-line descriptions. Most people don’t.

    The bigger issue: prompts drift

    Even if you solve retrieval, there’s a second problem. Prompts aren’t static. Models improve. Your writing style changes. The task evolves.

    The “write a newsletter intro” prompt you saved in February might produce worse output than a simpler prompt today, because GPT-4 in May behaves differently than GPT-4 in February. Or because you’ve tightened your house style and the old prompt encourages the wrong tone.

    If you’re saving every prompt variation, your library becomes a junk drawer. If you’re overwriting old prompts, you lose the ability to compare results or roll back when a new version underperforms.

    The cleanest solution I’ve seen: version prompts like code. Keep a changelog at the top of each prompt file. v1: original. v2: shorter intros. v3: removed rhetorical questions. When you update a prompt, you document why. Three months later, when output quality drops, you know which change to revert.

    This works in snippet tools, too—just add a version tag to your trigger. ;newsletter-intro-v3 instead of ;newsletter-intro. You keep the old version accessible without cluttering your main workflow.

    When to stop collecting prompts entirely

    Here’s the contrarian part: most solo operators would get better results from fewer saved prompts and more iteration in-session.

    If you’re saving fifty prompts for fifty micro-tasks, you’re fighting the way modern AI tools actually work. They’re conversational. They improve with feedback. A mediocre starting prompt plus two rounds of clarification often beats a “perfect” saved prompt used cold.

    The prompts worth saving are the ones that encode hard-won constraints—word counts, formatting rules, audience definitions, brand voice—that you’d otherwise have to re-explain every time. Everything else is just a starting point.

    Save the structure. Improvise the rest.

    Using AI tools to run your content operation? Subscribe to One Two Three Send for weekly breakdowns of what actually works—no hype, no fluff.

    Heads up — some links in this article are affiliate links. If you sign up through them, we may earn a small commission at no extra cost to you. We only recommend tools we use ourselves.

  • Course platforms leak money through hidden transaction limits

    Course platforms leak money through hidden transaction limits

    Most course creators pick a platform, upload their videos, and assume the checkout will work at any scale. Then they run a launch, hit a transaction threshold buried in the fine print, and watch sales freeze until the next billing cycle.

    These limits aren’t about storage or bandwidth—they’re about how many individual purchases your platform will process in a calendar month. Cross the line and you’re either locked out, auto-upgraded to a higher tier, or hit with overage fees that can double your hosting cost overnight.

    Where the walls are

    Teachable’s Basic plan ($59/month) caps you at 250 transactions per month. That’s total checkouts: course sales, upsells, payment-plan installments. If you sell a $97 course and 260 people buy it in October, the last ten get an error page unless you’re already on the Pro plan ($159/month), which raises the ceiling to 2,000 transactions.

    Thinkific’s Basic plan ($49/month) has no stated transaction cap, but it restricts you to one published course and one admin user. You hit scaling friction through feature gates, not checkout limits. The Start plan ($99/month) lifts most restrictions but still charges a $0.10 fee per enrollment if you use Thinkific Payments instead of connecting Stripe directly.

    Podia bundles email, courses, and digital downloads under one roof. Its Mover plan ($39/month) has no transaction cap and no platform fees—but you’re limited to one site and basic email automation. The Shaker plan ($89/month) adds affiliates, code editors, and advanced workflows, still with no transaction ceiling.

    Kajabi doesn’t publish a transaction limit, but its entry-tier pricing starts at $149/month for up to 10,000 contacts and 1,000 active members. You’re more likely to hit a contact-list cap than a sales cap, but both can shut down growth mid-funnel.

    What actually breaks

    Transaction limits don’t just stop new sales—they cascade. If you’re running a payment plan (three installments over 90 days), each installment counts as a separate transaction. A single buyer on a payment plan consumes three transaction slots, even though you only made one sale.

    Upsells and order bumps multiply the count too. Sell a course with a one-click upsell for templates, and that’s two transactions per buyer. Run a launch weekend with 200 buyers, half of whom take the upsell, and you’ve burned 300 transactions in 72 hours.

    Affiliate payouts don’t count toward transaction limits, but refunds do. Issue a refund in Teachable and it doesn’t refund your transaction count—you’ve still used the slot. If you’re near your cap and process ten refunds, those ten slots are gone until next month.

    How to plan around it

    Before you launch, calculate your expected transaction load. Multiply projected buyers by the number of transaction events per buyer: initial purchase, upsells, and any payment-plan installments. Add 20% margin for refunds and edge cases.

    If your platform caps transactions, map your pricing tier against your funnel. Teachable’s Pro plan at $159/month makes sense if you expect 500–2,000 transactions per month. Below that, you’re overpaying. Above that, you need the next tier or a migration plan.

    For payment plans, front-load as much revenue as possible. Offer a small discount for paying in full, or structure plans as two installments instead of three. Fewer installments mean fewer transaction events and more predictable capacity.

    Connect Stripe or PayPal directly when the platform allows it. Thinkific, Podia, and Teachable all support direct payment gateways, which often bypass per-transaction fees and give you more control over dispute handling and payout timing.

    When to switch platforms

    If you’re consistently hitting transaction caps, moving to a platform with no ceiling—or migrating to a self-hosted solution like WooCommerce or MemberPress—becomes cheaper than upgrading tiers every quarter.

    Self-hosting adds operational overhead: you’re responsible for uptime, PCI compliance (handled by Stripe, but you still configure it), and plugin updates. But you eliminate per-transaction fees and artificial caps. A $30/month WordPress host plus a $199/year membership plugin can handle 10,000 transactions a month without flinching.

    Before you migrate, export everything: customer lists, transaction history, course content, email sequences. Most platforms let you export CSVs and download video files, but automation rules and custom CSS don’t transfer cleanly. Budget two weeks for a clean migration, longer if you have complex funnels.

    If you’re planning a launch in the next 60 days, check your transaction cap today. Open your billing page, find the limit, and multiply your projected sales by the number of transaction events per buyer. If the math puts you within 20% of the cap, upgrade now—or risk going dark the day your launch peaks.

    Hit reply if you’ve been burned by a transaction cap mid-launch. I’m collecting war stories for a follow-up piece on platform migration triggers.

  • WordPress plugin auto-updates: which ones break sites in production

    WordPress plugin auto-updates: which ones break sites in production

    WordPress added automatic plugin updates in 2020. The pitch was simple: set it once, never worry about security patches again. But every operator who’s enabled auto-updates across the board has learned the same lesson—some plugins don’t play well with unattended updates, and the ones that break tend to break hard.

    The question isn’t whether to use auto-updates. It’s which plugins can be trusted to update themselves, and which need human review before they touch production.

    The plugin categories that auto-update safely

    Security plugins, spam filters, and utilities that don’t touch your front-end rendering are usually safe bets. Plugins like Wordfence, Akismet, and Redirection rarely introduce breaking changes because their scope is narrow and their update patterns are conservative.

    Same goes for plugins that handle single, well-defined tasks: backup tools, uptime monitors, analytics trackers. If the plugin doesn’t interact with your theme, doesn’t hook into checkout flows, and doesn’t modify post content, auto-update risk is low.

    I’ve run auto-updates on Wordfence, UpdraftPlus, and MonsterInsights across a dozen sites for two years without a single incident. These plugins update frequently, but they’re built with backwards compatibility in mind.

    The plugin categories that break silently

    Page builders, membership plugins, and ecommerce extensions are the opposite. These plugins hook into WordPress core rendering, modify database schemas, and depend on specific PHP versions or third-party APIs. When they update, they can break layouts, disable checkout, or lock users out of gated content.

    Elementor and WooCommerce are notorious for this. A minor version bump can introduce a CSS conflict that destroys mobile navigation, or a database migration that fails halfway through and leaves orders in limbo. Auto-updating these plugins on a revenue-generating site is a gamble.

    Same goes for plugins that modify admin workflows or add custom post types. If a plugin changes how your CMS behaves, you need to test the update in staging before it touches production. Auto-updates remove that step.

    The real cost of a bad auto-update

    A broken plugin doesn’t just throw an error message. It can take down your entire site, disable your email opt-in forms, or break your payment processor. If that happens at 11pm on a Friday, you’re either rolling back blind or losing revenue until Monday morning.

    I’ve seen a single WooCommerce auto-update disable checkout for six hours because the new version required PHP 7.4 and the host was still running 7.3. The plugin didn’t throw a warning—it just silently failed. The site owner only noticed because a customer emailed to say the cart was broken.

    That’s the problem with auto-updates: they assume your environment is compatible, your theme won’t conflict, and your custom code won’t break. None of those assumptions hold on a real site.

    How to decide which plugins get auto-updates

    Start by auditing your plugin list. Group them into three buckets:

    • Critical path: Plugins that handle revenue, user access, or content delivery. These need manual updates with staging tests first.
    • Front-end rendering: Plugins that modify your theme, inject CSS, or change layout. Auto-update risk is high.
    • Background utilities: Plugins that run cron jobs, log data, or handle security. These are usually safe to auto-update.

    For the critical-path plugins, disable auto-updates and set a monthly calendar reminder to update manually. For front-end plugins, test updates in a staging environment first—most hosts offer staging as a built-in feature now.

    For background utilities, enable auto-updates but configure uptime monitoring so you know immediately if something breaks. Tools like Jetpack Monitor or UptimeRobot are free and will email you within five minutes of downtime.

    The staging workflow that catches problems early

    If you’re running a content site with ad revenue or a membership site with gated access, you need a staging environment. Clone production once a week, enable auto-updates on staging only, and let it run for 48 hours. If nothing breaks, manually apply the same updates to production.

    This workflow adds one manual step, but it catches breaking changes before they hit live traffic. Most managed WordPress hosts—BigScoots, Kinsta, WP Engine—offer one-click staging environments and automated sync tools.

    If your host doesn’t support staging, use a plugin like WP Staging to create a local clone. It’s not as clean as a proper staging server, but it’s better than testing updates on production.

    The rule is simple: if a plugin touches revenue or user experience, test it first. If it runs in the background and doesn’t modify your front end, let it update itself. Everything else is a judgment call based on how much downtime you can tolerate.

    Want more WordPress infrastructure breakdowns like this? Reply with the hosting or plugin topic you’re trying to solve—we’ll cover it in a future issue.

  • Social media schedulers don’t understand momentum

    Social media schedulers don’t understand momentum

    Every social media scheduling tool sells the same dream: batch your content on Sunday, set it, forget it, and watch the engagement roll in. The reality is messier. Most schedulers are built for your convenience, not for the way social platforms actually distribute content.

    The gap between those two things costs you reach, replies, and revenue. Here’s why—and what operators who treat social as a revenue channel do differently.

    Algorithms reward immediate engagement, not post volume

    Instagram, LinkedIn, X, and Threads all prioritise posts that generate fast engagement in the first 30–90 minutes. A post that gets five likes in three minutes will be shown to more people than a post that gets fifty likes over six hours.

    Most scheduling tools drop your post at the appointed time and walk away. They don’t tell you it went live. They don’t surface replies. They don’t nudge you to engage with early comments. So your post sits there, algorithmically invisible, while you’re in a meeting or asleep.

    This is the momentum problem: the content goes out, but you’re not there to amplify it when it matters most.

    What “being there” actually looks like

    The operators I know who get consistent reach from social do three things most schedulers can’t automate:

    • They reply to comments in the first hour. Not just “thanks”—they ask follow-up questions, tag other accounts, extend the thread. Platforms interpret this as a signal that the post is worth showing to more people.
    • They repost or quote-tweet their own content 90 minutes later if it’s gaining traction. This isn’t spam; it’s recognising when something is working and giving it a second push while the algorithm window is still open.
    • They kill underperforming posts early. If a LinkedIn post has three likes after two hours, they delete it and try a different angle the next day. No point leaving low-engagement content on your profile where it trains the algorithm to show you to fewer people next time.

    None of this is possible if you’re batching twelve posts on a Sunday and forgetting about them until Friday.

    Tools that get closer to solving this

    A handful of schedulers have started building features that acknowledge the momentum problem, though none solve it completely.

    Publer sends you a mobile notification the moment your post goes live, and you can reply to comments directly in the app without opening six different social platforms. It’s not perfect—engagement still lags compared to posting natively—but it’s faster than logging into Buffer, realising a post went out two hours ago, and scrambling to reply.

    Typefully lets you queue “chain” posts on X, where the second tweet in a thread only goes out if the first one hits a certain engagement threshold. It’s a crude version of momentum-aware scheduling, but it’s something.

    Meta Business Suite (for Instagram and Facebook) has a “boost post” button that appears when a post is outperforming your average. You can turn $20 into 5,000 extra impressions in the same 90-minute window that matters algorithmically. Most third-party schedulers don’t surface this option at all.

    The manual workflow that still beats automation

    Here’s what works for solo operators who don’t have a social media manager: schedule the post, but block 15 minutes on your calendar starting five minutes after it goes live.

    In those 15 minutes:

    • Reply to every comment, even if it’s just a sentence.
    • Share the post to your Instagram story or LinkedIn with a one-sentence callout.
    • DM it to two or three people you know will engage.

    This isn’t scalable if you’re posting ten times a day. But if you’re posting once a day on two platforms—which is what most indie operators actually do—it’s 30 minutes of work that doubles your reach.

    The scheduler gets the post out on time. You handle the momentum. That division of labor is honest about what software can and can’t do.

    What this means for your workflow

    If social is a meaningful traffic or revenue channel for you, treat the first 90 minutes after a post goes live as sacred. Don’t batch-and-forget. Don’t let the post sit while you’re in another tab.

    If you can’t be there in the first 90 minutes, don’t schedule the post for that time. Move it to a slot where you’ll actually be available. A post that goes out at 11 a.m. with you present will outperform a post that goes out at the “optimal” 9 a.m. time with you absent.

    Scheduling tools are useful. But they’re not a substitute for showing up when your content needs you most.

    One Two Three Send covers the tools and workflows that solo operators actually use to run content businesses. Subscribe to get one article like this in your inbox every morning.

    Heads up — some links in this article are affiliate links. If you sign up through them, we may earn a small commission at no extra cost to you. We only recommend tools we use ourselves.

  • ConvertKit’s subscriber tagging limit and how to work around it

    ConvertKit doesn’t advertise it loudly, but there’s a hard limit: 10,000 tags per subscriber. For most operators, that sounds absurdly high. But if you’ve been running automations for a year or more—especially if you tag based on link clicks, form submissions, or purchase behavior—you can hit it faster than you think.

    When you do, ConvertKit silently stops applying new tags to that subscriber. No error message in the UI. No email alert. The automation runs, the subscriber moves through the sequence, but the tag never lands. You only notice when a segment comes up empty or a conditional split sends someone down the wrong path.

    How you hit the limit without realizing it

    The most common culprit: date-stamped tags. If you’re tagging subscribers with things like clicked_link_2024-05-15 or opened_email_january_2026, you’re creating a new tag every single day or week. Multiply that across a dozen automations, and a subscriber who’s been on your list for 18 months can easily accumulate 3,000+ tags.

    Link-click tracking is another one. If you tag every link click with a unique identifier—say, clicked_affiliate_link_productA, clicked_affiliate_link_productB, and so on—you’re burning through your tag budget fast, especially if you publish daily or run frequent promotions.

    Purchase tags are safer, but only if you’re disciplined. Tagging purchased_course_A is fine. Tagging purchased_course_A_via_email_campaign_spring2026 is not. The more specific you get, the faster you hit the ceiling.

    How to audit your current tag usage

    ConvertKit doesn’t surface per-subscriber tag counts in the dashboard, so you’ll need to export your subscriber list and count manually. Go to Subscribers → Export, download the CSV, and open it in Google Sheets or Excel. Each subscriber row will have a Tags column with a comma-separated list.

    Use a formula like =LEN(A2)-LEN(SUBSTITUTE(A2,",",""))+1 to count how many tags each subscriber has. Sort descending. If anyone’s above 8,000, you’re close to the edge.

    While you’re in there, scan for patterns. Look for date-stamped tags, redundant event tags, or anything that increments indefinitely. Those are your cleanup targets.

    Two strategies to stay under the limit

    Strategy one: replace incremental tags with custom fields. Instead of tagging last_clicked_2026-05-24, create a custom field called last_click_date and update it with each action. Custom fields don’t count toward the tag limit, and you can still segment or filter by date. The tradeoff: you lose the historical record. If you need to know every date someone clicked, this won’t work. But if you only care about the most recent action, it’s cleaner.

    Strategy two: archive old tags in bulk. ConvertKit lets you remove tags from subscribers, but there’s no native “delete all tags older than X date” feature. You’ll need to export, filter by tag name pattern (e.g., anything containing 2024), then use the bulk actions menu to remove those tags from the affected subscribers. This is manual, but if you do it quarterly, it keeps your tag count manageable.

    One more option: if you’re tagging for analytics purposes—tracking which emails drove the most clicks, for example—consider moving that data out of ConvertKit entirely. Tools like Plausible or Fathom can track link clicks via UTM parameters, and you won’t burn tags on behavior you’re only measuring, not acting on.

    When the limit actually matters

    For most solo operators, 10,000 tags per subscriber is still overkill. If you’re running a simple welcome sequence, a few product-based segments, and occasional broadcasts, you’ll never get close. The limit only becomes a problem if you’re running complex, multi-branch automations that tag aggressively at every decision point.

    But if you are in that category—if you’re running a membership site, a course platform, or a content business with dozens of lead magnets and automations—this is worth auditing now, before a subscriber silently stops receiving the tags that trigger your most important sequences.

    Want more feature breakdowns like this? Subscribe to One Two Three Send for weekly deep dives on the tools that run your online business—no fluff, just the mechanics that matter.

  • Zapier’s Digest feature: batch updates without spamming your inbox

    Zapier’s Digest feature: batch updates without spamming your inbox

    Most automation workflows fire once per trigger. Someone fills out a form, Zapier fires. A new row hits your sheet, Zapier fires again. That’s fine when you get three events a day. It’s a disaster when you get thirty.

    Zapier’s Digest step exists to solve that problem. Instead of sending you a Slack notification for every new subscriber or a separate email for every form submission, Digest collects those events over a set time window—hourly, daily, or weekly—and bundles them into a single payload.

    It’s one of Zapier’s least-documented features, and most operators don’t know when to use it or how to configure it properly. Here’s what it does, when it works, and one setup mistake that breaks the entire workflow.

    How Digest actually works

    Digest sits between your trigger and your action. Every time the trigger fires, Zapier adds that event to a temporary storage queue instead of immediately passing it downstream. When your chosen time window closes—say, every day at 9 a.m.—Zapier releases the entire batch as a single step output.

    You configure three things: the digest key, the time interval, and the data format. The digest key groups events together; if you’re batching form submissions by type, you’d use a key like form_name. The time interval sets when the batch releases: every hour, every day at a specific time, or every week on a chosen day. The data format determines whether Zapier sends a line-item list or a concatenated text block.

    Common use cases: daily summary emails of new subscribers, weekly Slack digests of GitHub issues, hourly rollups of customer support tickets. Anywhere you’d rather see ten items at once than ten separate notifications.

    When batching saves time, and when it hides problems

    Digest works best when the underlying event is informational rather than urgent. If you’re tracking new blog comments or monitoring social mentions, a daily rollup keeps your inbox clean without missing anything critical.

    It breaks down when the event requires immediate action. If you’re using Digest to batch payment failures or security alerts, you’ve just introduced a delay that could cost you money or trust. A payment fails at 10 a.m., but you don’t see it until the 5 p.m. digest fires—by then, the customer has already churned or disputed the charge.

    The other failure mode: data overload. If your digest regularly contains 50+ items, you’re not reading it—you’re archiving it. At that point, Digest isn’t solving a notification problem; it’s hiding a workflow problem. You probably need filtering, segmentation, or a different tool altogether.

    The setup mistake that silently breaks Digest

    Here’s the trap: Digest only works if your Zap actually runs during the release window. If your trigger hasn’t fired in the past 24 hours and you’ve set a daily digest, Zapier won’t release the batch—it needs at least one new event to trip the release logic.

    That means if you’re batching low-frequency events—say, a weekly digest of new affiliate signups—you could end up with no output at all if no one signed up that week. Zapier won’t send an empty digest; it just skips the release entirely.

    The workaround: pair Digest with Zapier’s Schedule trigger instead of relying on the original event trigger. Set a daily or weekly schedule, then pull the digest data manually via a Formatter step or a webhook. This guarantees the release window fires even when the source data is quiet.

    One non-obvious configuration tip

    Most operators set their digest interval to align with their own schedule—daily at 9 a.m., for example. That’s fine for personal workflows, but if you’re sending digests to a team or a client, you want the release time to match their context, not yours.

    If you’re summarising support tickets for a remote team across three time zones, a single 9 a.m. UTC digest lands at 4 a.m. for some people and lunchtime for others. Instead, duplicate the Zap and configure separate digests for each region, or use Zapier’s Paths feature to route events into time-zone-specific buckets before they hit Digest.

    And if you’re batching user-facing data—like a weekly email summarising content performance for your readers—test the digest output format carefully. Zapier’s default line-item formatting often includes raw field names and extra punctuation that looks fine in Slack but breaks in an HTML email template. You’ll need a Formatter step after Digest to clean it up.

    When to skip Digest entirely

    Two situations where Digest isn’t the right tool: when you need conditional logic per event, and when your downstream action can already handle bulk data.

    If you’re filtering events based on custom field values—say, only sending a notification when a form submission includes a specific keyword—you need to apply that filter before Digest, not after. Otherwise, you’re batching everything and then discarding most of it, which wastes task usage and complicates your Zap history.

    And if your action step already supports bulk operations—like updating multiple rows in a Google Sheet or sending a batch email via an API—you don’t need Digest at all. Use Zapier’s native Looping or Line Item handling instead, which gives you more control over error handling and retry logic.

    Digest is useful, but it’s not universal. The best automation workflows batch strategically, not reflexively.

    Want more breakdowns like this? Reply and tell me which Zapier step or automation pattern you want explained next—I’ll cover it in a future issue.

  • Beehiiv’s paid subscriptions: setup, fees, and the VAT surprise

    Beehiiv’s paid subscriptions: setup, fees, and the VAT surprise

    Beehiiv launched native paid subscriptions in 2023, positioning itself as the all-in-one platform that doesn’t need Stripe integration or third-party membership plugins. For operators already using Beehiiv for free newsletters, flipping the paid switch looks frictionless. But the setup hides complexity that surfaces once you start collecting money across borders.

    Here’s what actually happens when you turn on paid subscriptions, what it costs, and the tax issue that catches most operators off guard.

    How Beehiiv paid subscriptions work

    Beehiiv handles payment processing, subscriber management, and content gating in one interface. You set your price—monthly, annual, or both—and designate which posts are free versus paid. Beehiiv uses Stripe under the hood but abstracts the integration: you connect your Stripe account once during setup, and Beehiiv manages checkout, invoicing, and failed payment recovery.

    The platform supports tiered pricing, free trials, and discount codes. You can also gate individual posts retroactively, which is useful if you’re testing paid content before fully committing to a subscription model.

    One non-obvious benefit: Beehiiv’s referral program integrates with paid tiers. If a free subscriber refers enough readers, they can unlock paid content without paying. This works well for growth-focused operators who want to reward evangelists, but it complicates revenue forecasting—your paid subscriber count and MRR won’t always move in lockstep.

    The fee structure

    Beehiiv takes a 2.9% platform fee on top of Stripe’s standard processing fees (2.9% + $0.30 per transaction in the U.S.). That means you’re paying roughly 5.8% + $0.30 per transaction when someone subscribes.

    For a $10/month subscription, you net around $9.12 after fees. At $100/month, you keep $94.12. The percentage hit is consistent, but the flat $0.30 fee stings more on lower-price subscriptions.

    Beehiiv’s fee applies to your plan tier, not your revenue size. Whether you’re on the Scale plan ($99/month) or Launch (free), the 2.9% fee remains. This is different from platforms like Substack, which take 10% but don’t charge a base platform fee.

    If you process $5,000/month in subscriptions, Beehiiv’s cut is $145. Substack’s would be $500. The breakeven point sits around $3,500/month in subscription revenue—below that, Beehiiv’s model costs less; above it, the flat percentage wins.

    The VAT problem nobody mentions upfront

    Beehiiv does not automatically handle VAT, GST, or sales tax collection for non-U.S. subscribers. If you have paying subscribers in the EU, UK, Australia, or other VAT-registered regions, you are responsible for compliance.

    Stripe can calculate and remit taxes if you enable Stripe Tax, but Beehiiv’s integration doesn’t surface this option in the dashboard. You have to configure it directly in your Stripe account, then ensure Beehiiv passes the correct billing address data to Stripe during checkout.

    Most operators discover this after their first invoice from a European subscriber. If you’re not charging VAT and you cross registration thresholds (€10,000 in EU sales), you’re technically operating outside compliance. Fixing it retroactively means either absorbing the tax yourself or awkwardly re-invoicing subscribers.

    If you’re U.S.-based and expect most subscribers to be domestic, this may not matter in year one. But if you’re writing for a global audience, budget time to either enable Stripe Tax or work with an accountant who understands digital service VAT rules.

    When to use Beehiiv paid vs. an external membership tool

    Beehiiv’s native subscriptions work best when:

    • Your entire business is the newsletter—no courses, downloads, or community access
    • You want one dashboard for content, audience, and revenue
    • You’re okay with Beehiiv owning the checkout experience and subscriber relationship

    Skip Beehiiv paid and use a dedicated membership platform (Memberful, Ghost, or a WordPress membership plugin) if:

    • You need complex access rules—time-limited content, drip courses, or tiered community access
    • You want full control over tax settings, invoicing, and subscriber data portability
    • You plan to sell more than just newsletter access (e.g., templates, coaching, or archived resources)

    Beehiiv’s model is fast to launch but rigid once you outgrow simple “free vs. paid” segmentation. Migrating paying subscribers off the platform later is possible, but it requires CSV exports, manual Stripe imports, and subscriber communication to avoid confusion or churn.

    If you’re testing paid for the first time and already use Beehiiv, the native option is the fastest validation path. Just know the tax setup isn’t automatic, and the 2.9% fee is a permanent cost unless you move to a different platform.

    Using a different newsletter platform or thinking about switching? Reply and let me know what’s working—or not—in your paid subscription stack. I’ll cover more monetization mechanics in future issues.

    Heads up — some links in this article are affiliate links. If you sign up through them, we may earn a small commission at no extra cost to you. We only recommend tools we use ourselves.

  • Subscription bombing: why bots sign up to your newsletter (and how to block them)

    Subscription bombing: why bots sign up to your newsletter (and how to block them)

    If you run a newsletter, you’ve probably noticed signups appearing in your subscriber list with email addresses that look subtly wrong. Names you don’t recognise. Local-parts with strange dot patterns like [email protected]. All marked as “direct” with no referer, no UTM, no obvious traffic source.

    These aren’t your audience. Your site is being used as a relay in an attack on someone else’s inbox. The technical name is subscription bombing (also called list bombing or mail bombing), and once you know what to look for, you’ll see it on almost every newsletter signup form on the open web.

    What subscription bombing actually is

    An attacker picks a victim — usually one specific email address. They run a bot that visits thousands of unrelated websites that accept newsletter signups and submits the victim’s email to every one of them.

    Within ten minutes, the victim’s inbox fills with two hundred legitimate-looking welcome emails from newsletters they never signed up for. Travel sites, ecommerce stores, hobby blogs, university mailing lists, charity newsletters. Each individual email is innocuous. The pile is the point.

    Your site isn’t being attacked. Your site is being used as a small, expendable cog in an attack on someone you’ve never met.

    Why attackers do this

    The motive is almost always to hide a single critical email from the victim:

    • Credit card fraud cover. The attacker just made a $2,000 purchase on the victim’s stolen card. The bank will send a fraud-alert email within minutes. If that alert is buried under 300 newsletter confirmations, the victim might not see it until after the cancellation window closes.
    • Account recovery. The attacker is trying to take over the victim’s email or banking account. Password-reset confirmations and 2FA codes get buried in the same way.
    • Harassment. Less common, but bombings are sometimes used to make a target’s inbox unusable for days.

    There are services that openly sell this. “1,000-site mail bomb, $30.” They use rented botnets so the requests come from thousands of residential IPs — no single source to block.

    How to spot it on your own list

    Two patterns are diagnostic:

    The dotted-Gmail trick

    Gmail ignores dots in the local-part of an address. [email protected], [email protected], and [email protected] all deliver to the same inbox. Each site’s database stores them as distinct addresses (so per-site dedup doesn’t catch the second signup), but the victim receives every email.

    If you see several Gmail signups in the same short window with unusual dot patterns, those are almost certainly bot signups. Real humans don’t sprinkle random dots through their own email when filling out a form.

    Missing referer, missing UTM, sub-minute conversion

    Bots that target your endpoint directly never load the form page first. They POST straight to the subscribe endpoint with just {email}. As a result:

    • No Referer header.
    • No utm_source on the landing URL.
    • No first-touch attribution cookie.
    • “First seen” and “subscribed” timestamps within seconds of each other.

    A real visitor might land via Facebook, browse for a few minutes, then sign up. Their attribution captures something. Bots leave nothing.

    Layered defences that actually work

    No single check stops subscription bombing. The pattern is layered defences, each catching a slightly different bot class:

    1. Honeypot field. A hidden input field that real humans never see. Bots that scrape the form HTML and fill every input get caught. Cheap, transparent, zero UX impact. Useless against bots that POST straight to the endpoint without loading the form.
    2. Per-IP rate limit. N submissions per IP per hour. Catches bursty single-IP attacks. Useless against distributed botnets across thousands of residential IPs.
    3. MX-record check. Reject signups whose email domain has no MX (mail exchanger) record. Catches typos and made-up domains. Cheap — one DNS lookup. Useless against Gmail-based attacks.
    4. Disposable-domain blocklist. Reject signups from known throwaway services (mailinator, guerrillamail, yopmail, etc.). Useless against real-domain attacks but kills another bot class.
    5. Gmail dot-normalization. Strip dots from the local-part of Gmail addresses before storing. If [email protected] already exists, the second variant gets rejected as a duplicate. Catches dot-trick attacks on a single site (though not across multiple sites).
    6. Cloudflare Turnstile. Invisible CAPTCHA. By far the most effective single layer — it makes bot signups dramatically more expensive to attempt. Some UX cost: real users with strict privacy extensions occasionally fail it.
    7. Double opt-in. Send a confirmation email; only add the subscriber once they click. The standard ESP defence. It doesn’t prevent the bomb (you still send one email) but it stops the victim from being added to your ongoing list, which protects your sender reputation downstream.

    Each layer should silently accept-and-drop suspicious signups — return HTTP 200, never reveal which check tripped. If your endpoint says “rate limited” or “honeypot detected,” attackers immediately adapt.

    What One Two Three Send does out of the box

    As of version 2.0.20, the free plugin’s /wp-json/otts/v1/subscribe endpoint runs four layers automatically:

    • Honeypot on the form (hidden website input — already in earlier versions).
    • Per-IP rate limit — 10 submissions per IP per hour by default, filterable via otts_subscribe_rate_limit_per_hour.
    • MX-record validation on the email domain.
    • Disposable-domain blocklist of ~30 common throwaway services, filterable via otts_subscribe_disposable_domains.

    All four layers silently accept-and-drop — bots can’t fingerprint which check rejected them.

    The Subscribers admin page now has a Delete button on every row for cleaning up signups that slip through. Two new admin-only REST endpoints (DELETE /wp-json/otts/v1/subscriber/{id} and POST /wp-json/otts/v1/subscriber/delete-by-email) let you script bulk cleanups if you need to delete dozens of bot signups at once.

    If your site is being bombed heavily, Cloudflare Turnstile in front of your signup form is the next step. It’s free, integrates in a few lines of JS, and stops the overwhelming majority of attacks that get past the layers above. Double opt-in is the layer after that.

    One thing worth keeping in mind

    If you see fifty bot signups appear in your list, your first reaction will probably be annoyance about list-hygiene. The bigger picture is that fifty real people — strangers, somewhere — just had their inboxes flooded as cover for a fraud or account-recovery attack. Tightening up your form isn’t just protecting your sender reputation. It’s removing one of the small relays that subscription-bombing services rent out by the thousand.

    Every site that adds a honeypot, a rate limit, or a Turnstile widget makes that business model a little less profitable. That’s worth doing.

  • Paid search vs. organic content: which builds revenue faster?

    Paid search vs. organic content: which builds revenue faster?

    Every solo operator hits the same fork in the road: spend money on Google Ads to get traffic today, or invest time in SEO to earn it for free six months from now.

    The conventional advice—”do both”—ignores the reality of limited budgets and single-person operations. You need to pick one, at least to start. Here’s how to make that call based on your business model, your offer, and your tolerance for waiting.

    When paid search wins

    Google Ads gets you in front of buyers the day you launch a campaign. If you’re selling a productised service, a course, or a SaaS tool with a proven conversion rate, paid search lets you test messaging, validate demand, and generate revenue while your content strategy is still a Notion doc.

    The break-even math is simple: if your customer lifetime value is $500 and you can acquire a customer for $150 via Google Ads, you’re profitable from day one. That margin funds more ads, more tests, and eventually the content team you wish you had time to build.

    Paid search also works when your market is narrow and your keywords are cheap. A consultant selling fractional CFO services to SaaS founders can buy “fractional CFO for SaaS” at $8 per click and convert at 5%. That’s $160 per customer—sustainable if the contract is worth $3,000.

    But paid search stops the moment you stop paying. Your cost per acquisition never improves structurally; you’re renting attention, not owning it. And if your offer doesn’t convert above 2%, or your LTV is under $200, the unit economics collapse fast.

    When organic content wins

    SEO is a compounding asset. Publish 50 articles that rank, and they generate traffic—and revenue—for years without additional spend. A tutorial on “how to migrate from Mailchimp to ConvertKit” can drive 400 visits a month for three years, converting 2% of readers into affiliate commissions or newsletter subscribers.

    Organic content works best when you’re building an audience business—newsletters, memberships, affiliate income—or when your product has a long sales cycle. If buyers need to read six articles before they trust you enough to book a call, SEO is feeding that funnel for free while paid ads burn budget on cold traffic.

    The trade-off is time. Expect six months before you see meaningful traffic, and twelve before it becomes a dependable revenue channel. You’re also competing with sites that have been publishing for a decade. Ranking for “email marketing tips” is nearly impossible; ranking for “Beehiiv vs. ConvertKit for paid newsletters” is achievable in 90 days.

    SEO also favours operators who can write. If you’re paying $300 per article to a freelancer, your payback period stretches to 18 months. If you’re writing yourself at 1,000 words per hour, the math tilts in your favour.

    The hybrid play most operators miss

    Here’s the move that works if you have $500/month to spend: run Google Ads on your three highest-intent keywords while you build out the content that will eventually rank for them organically.

    The paid campaign generates revenue and validates which keywords actually convert. The organic content builds slowly in the background. After six months, your articles start ranking, your cost per click drops as organic traffic offsets paid volume, and you can reallocate ad spend to new keywords or turn it off entirely.

    This only works if your paid campaigns are profitable from week one. If you’re losing money on ads while waiting for SEO to kick in, you’re just burning capital in two directions.

    How to choose right now

    If your offer converts above 3%, your LTV exceeds $300, and you need revenue this quarter, start with paid search. Build a single campaign around five keywords, set a $20/day budget, and measure cost per acquisition weekly.

    If you’re pre-revenue, building an audience, or selling something with a six-month consideration cycle, start with organic content. Publish two articles per week for 90 days, target long-tail keywords with under 500 monthly searches, and track rankings in Google Search Console.

    If you’re somewhere in between, run a one-month paid test with a $300 budget. If your CPA is under half your LTV, keep running ads and layer in content. If it’s not, kill the campaign and go all-in on SEO.

    Want more breakdowns like this? Subscribe to One Two Three Send for weekly tactics on traffic, tools, and revenue—written for operators who don’t have a marketing team.

    Heads up — some links in this article are affiliate links. If you sign up through them, we may earn a small commission at no extra cost to you. We only recommend tools we use ourselves.

  • WordPress cron jobs: what runs when and how to fix the slowdowns

    WordPress cron jobs: what runs when and how to fix the slowdowns

    WordPress cron is a lie. It’s not a scheduled task runner—it’s a script that fires when someone visits your site. If nobody visits for an hour, nothing runs for an hour. If fifty people hit your homepage at once, that script might try to run fifty times simultaneously.

    That’s why your admin dashboard sometimes loads slowly, or why your scheduled posts don’t publish at the exact minute you set. Understanding what WordPress cron actually does—and when to replace it—matters once you’re running a content operation that depends on predictable publishing and performance.

    What WordPress cron actually runs

    Every WordPress install has a default set of cron jobs baked in. These include:

    • Checking for plugin and theme updates
    • Publishing scheduled posts
    • Clearing expired transients (temporary data stored in your database)
    • Sending pingbacks and trackbacks
    • Running database cleanup tasks

    Plugins and themes add their own jobs on top of this baseline. Newsletter plugins schedule digest sends. Backup plugins queue nightly snapshots. SEO plugins refresh sitemaps. Social-sharing tools check for new posts to auto-tweet.

    You can see every scheduled task by installing the WP Crontrol plugin. It lists every job, its recurrence interval, and the function it calls. On a typical site with a dozen active plugins, you’ll find twenty to forty jobs running hourly, daily, or weekly.

    Why it slows your site down

    WordPress cron fires on page load. When a visitor requests a page, WordPress checks if any cron jobs are due. If they are, it spawns a background HTTP request back to itself to process them.

    That works fine for low-traffic blogs. But once you’re running a content site with consistent traffic, you hit two problems:

    Multiple simultaneous triggers. If ten people load your homepage within the same second, WordPress might spawn ten parallel cron processes. Those processes compete for database connections and CPU. Your server slows down. Page load times spike.

    Cron jobs that block rendering. Some poorly-coded plugins don’t spawn the background request correctly. Instead, they run their cron tasks inline—before the page finishes loading. A five-second backup task means a five-second delay before your visitor sees anything.

    The standard fix is to disable WordPress cron entirely and replace it with real server-level cron.

    How to replace it with real cron

    Disabling WordPress cron takes one line in your wp-config.php file:

    define('DISABLE_WP_CRON', true);

    Add that above the line that says “That’s all, stop editing!” and save the file. WordPress will stop checking for due tasks on every page load.

    Now you need to tell your server to run those tasks instead. Most shared hosts and managed WordPress hosts (including BigScoots) let you add cron jobs through cPanel or a similar control panel.

    Create a new cron job that runs every five or ten minutes, pointing to:

    wget -q -O - https://yourdomain.com/wp-cron.php?doing_wp_cron >/dev/null 2>&1

    Or, if your host supports it:

    php /path/to/your/wordpress/wp-cron.php

    The first version uses HTTP to trigger the cron script, just like WordPress does—but on a predictable schedule instead of on every page load. The second version runs it directly via PHP, which is faster and doesn’t consume an HTTP request slot.

    Check your host’s documentation or ask support which syntax to use. Most managed WordPress hosts already handle this for you if you disable WP_CRON in config.

    When to leave WordPress cron enabled

    If your site gets fewer than a hundred visits per day, the default behavior is fine. The overhead is negligible, and you avoid the hassle of configuring server-level cron access.

    If you’re on a staging site or local development environment, leave it on. You need to visit the site to trigger tasks anyway, and setting up real cron for ephemeral environments isn’t worth it.

    But if you’re publishing on a schedule, running automated workflows, or seeing unexplained slowdowns during traffic spikes, disable WP_CRON and hand the job to your server. You’ll get predictable task execution and faster page loads.

    One non-obvious tip: After you switch to real cron, check WP Crontrol again in a week. Some plugins re-register their tasks incorrectly and create duplicates. If you see the same job listed twice with different intervals, delete the duplicate manually. It won’t break anything—the plugin will recreate the correct version on its next run.

    If this helped, subscribe to One Two Three Send for weekly breakdowns of the tools and infrastructure that actually matter when you’re running a content business solo.