Author: onetwothreeadmin

  • Stripe checkout session expiration: how long customers have to pay

    Stripe checkout session expiration: how long customers have to pay

    Stripe checkout session expiration: how long customers have to pay
    Photo by Ze Vieira on Unsplash

    If you’re selling digital products, courses, or subscriptions through Stripe, you’ve probably sent customers to a checkout session URL. What you might not know is that those URLs don’t last forever—and the default expiration window catches more operators off guard than it should.

    Stripe checkout sessions expire 24 hours after creation by default. If a customer clicks your payment link on Monday afternoon but doesn’t complete the purchase until Wednesday, they’ll see an error page. No purchase, no conversion, and you’ll never know they tried unless you’re watching session analytics closely.

    What checkout session expiration actually controls

    When you create a Stripe checkout session—either via API or through a payment link—Stripe generates a unique URL tied to that session ID. The expiration timer starts immediately, whether the customer has opened the link yet or not.

    The expires_at parameter defaults to 24 hours from creation. You can extend it to a maximum of 90 days by passing a Unix timestamp when you create the session:

    expires_at: Math.floor(Date.now() / 1000) + (7 * 24 * 60 * 60)

    That example sets expiration to seven days out. If you’re sending payment links via email, SMS, or embedding them in automated workflows, seven days is a safer window than one.

    Once a session expires, Stripe won’t accept payment through that URL. The customer sees a generic “This payment link is no longer valid” message. There’s no automatic redirect, no retry logic, and no way to extend the session retroactively. You’ll need to generate a new checkout session and send a fresh link.

    When short expiration windows backfire

    The 24-hour default makes sense if you’re generating checkout links dynamically at the moment a customer clicks “Buy Now” on your site. But it breaks down in three common scenarios:

    Email campaigns. If you’re sending a product launch email to 5,000 subscribers with an embedded checkout link, some will open that email three days later. The link is already dead. You’ll see click activity in your email analytics but zero corresponding Stripe sessions.

    Abandoned cart recovery. You send a reminder email 48 hours after someone adds a product to their cart. The original checkout session you generated is expired. The recovery email drives traffic to a broken link.

    Multi-step onboarding flows. A new user signs up, receives a welcome email with a payment link, then takes four days to complete onboarding and decide to subscribe. Expired. You’ve lost the conversion unless you trigger a new session programmatically when they return.

    How to set expiration based on your funnel

    If you’re generating checkout sessions via Stripe’s API, pass expires_at explicitly. Here’s the decision tree most operators settle on:

    • Same-session purchases (customer clicks Buy Now and checks out immediately): 24 hours is fine.
    • Email or SMS payment links: 7 days minimum. Some operators go 14.
    • Evergreen product pages or affiliate links: 30–90 days if you’re generating static links and don’t want to refresh them manually.

    If you’re using Stripe Payment Links (the no-code option in the Dashboard), you don’t control expiration—they’re permanent by default unless you manually deactivate them. That’s actually an advantage if you’re embedding links in automated emails or posting them publicly.

    The trade-off: Payment Links don’t support advanced session parameters like custom metadata per checkout or dynamic tax calculation. If you need that, you’ll need to generate sessions via API and manage expiration yourself.

    One non-obvious detail: expired sessions still appear in your Dashboard

    Even after a session expires, Stripe keeps the record visible in your Dashboard under Payments → Checkout Sessions. The status reads expired, but you can still see when it was created, what product was attached, and whether the customer opened the link (Stripe tracks that via a checkout.session.viewed webhook event).

    If you’re debugging conversion drop-off, filter your sessions by status: expired and compare the count to status: complete. A high expired-to-complete ratio often means your expiration window is too short for your funnel velocity.

    One more thing: expired sessions do not trigger a webhook. If you’re relying on webhooks to update user records or send follow-up emails, you won’t get notified when a session times out. You’ll need to poll session status via the API or set up a scheduled job to catch stale sessions before they expire.

    Want more operator-level breakdowns of tools, workflows, and pricing details? Subscribe to One Two Three Send—every article unpacks one specific mechanism that online-business operators actually need to understand.

  • Reddit’s API pricing killed third-party tools—but RSS still works

    Reddit’s API pricing killed third-party tools—but RSS still works

    Reddit's API pricing killed third-party tools—but RSS still works
    Photo by Brett Jordan on Unsplash

    Reddit’s 2023 API pricing changes forced Apollo, RIF, and a dozen other third-party clients to shut down. The fallout hit solo operators hardest: social listening dashboards, content aggregation tools, and automated posting workflows all broke overnight unless you could justify enterprise-tier API costs.

    Most operators can’t. Reddit’s Developer Platform pricing starts at $0.24 per 1,000 API calls after a 100-call daily free tier. If you’re monitoring a dozen subreddits for content ideas or tracking brand mentions across 50 threads per day, you’ll hit the cap in under a week. Scale to automation or multi-account management, and you’re looking at $12,000+ annually.

    But Reddit’s RSS feeds—an older, quieter feature—still work. They’re unmetered, require no authentication, and return clean XML you can parse with any feed reader or workflow tool. They won’t replace a full API integration, but for content monitoring, trend research, and lightweight automation, RSS covers 80% of what solo operators actually need.

    How Reddit RSS feeds work

    Every subreddit, user profile, and search query has an RSS endpoint. Append .rss to almost any Reddit URL:

    • reddit.com/r/SaaS/.rss — all posts in r/SaaS
    • reddit.com/r/SaaS/new/.rss — sorted by new
    • reddit.com/r/SaaS/search.rss?q=pricing&restrict_sr=1 — search results within a subreddit
    • reddit.com/user/username/.rss — a user’s public post history

    Feeds return the 25 most recent items. No pagination, no historical backfill. Reddit updates feeds every few minutes, but there’s no guaranteed refresh interval. For monitoring breaking discussions, expect a 5–15 minute lag.

    You don’t need an API key. You don’t need OAuth. You don’t need a developer account. Just fetch the URL and parse the XML.

    What you can (and can’t) do with RSS

    RSS works for:

    • Monitoring subreddits for content ideas or competitor mentions
    • Aggregating niche community discussions into a single feed reader
    • Triggering Zapier or Make workflows when keywords appear in post titles
    • Pulling top posts into a weekly digest or Slack channel

    RSS doesn’t give you:

    • Comment threads (only top-level post data)
    • Vote counts, upvote velocity, or ranking signals
    • The ability to post, reply, or interact programmatically
    • More than 25 items per feed

    If you need to analyze engagement metrics, scrape comment sentiment, or automate posting, you’re back to the paid API or manual workflows. But if your goal is awareness—knowing what’s being discussed, when, and by whom—RSS handles it.

    The reliability question

    Reddit hasn’t officially deprecated RSS, but they haven’t promoted it in years. The feature predates the 2023 API lockdown and wasn’t part of the pricing announcement. That makes it both useful and precarious.

    There’s no SLA. No public roadmap. No guarantee Reddit won’t shut it down next quarter to push more traffic through the official app and API tiers. Operators who built RSS-dependent workflows in 2024 are watching for signs: feed downtime, format changes, or silent rate-limiting.

    So far, the feeds are stable. Anecdotally, I’ve seen zero throttling on personal projects polling 40+ subreddit feeds every 15 minutes via Feedly and Zapier. That doesn’t mean Reddit won’t change course, but it does mean the feature isn’t being aggressively sunsetted yet.

    If you’re considering an RSS-based Reddit workflow, build with an exit plan. Use a feed reader or automation tool that lets you swap sources quickly. Don’t hard-code Reddit URLs into customer-facing products. Treat RSS as a time-limited workaround, not infrastructure.

    Practical setup

    The simplest approach: drop Reddit RSS URLs into Feedly, Inoreader, or any standard feed reader. Tag by topic, filter by keyword, and review daily.

    For automation, connect RSS to Zapier, Make, or n8n. Trigger actions when a post title matches a keyword or when a subreddit publishes anything new. Example: new post in r/SaaS containing “launch” → send to Slack → log in Notion.

    If you’re comfortable with code, fetch the .rss endpoint with a standard HTTP client, parse the XML, and filter in your own pipeline. No auth headers, no token refresh, no SDK to maintain.

    Reddit’s RSS feeds aren’t a substitute for real API access, but they’re a functional stopgap while the platform’s developer ecosystem remains priced out of reach for most solo operators. Use them while they last.

    Running a content-driven business? One Two Three Send covers tools, workflows, and operator tactics every week. Subscribe here.

  • Sponsored content briefs: what brands actually send you

    Sponsored content briefs: what brands actually send you

    Sponsored content briefs: what brands actually send you
    Photo by Annie Spratt on Unsplash

    The first time a brand sends you a sponsorship brief, it doesn’t look like the simple “mention us in your next post” pitch you expected. It’s a PDF with sections titled Messaging Guidelines, Exclusivity Window, and Usage Rights—and half of it contradicts what the sales rep told you over email.

    Here’s what you’ll actually see when a brand commits to sponsoring your content, and which parts you need to read twice before signing.

    The deliverables grid

    Most briefs open with a table: one column for asset type, one for quantity, one for due date. A typical $2,000 sponsorship for a newsletter operator might list:

    • One dedicated email send (minimum 500 words)
    • Two social posts (one Instagram, one Twitter/X)
    • One permanent blog post with dofollow link
    • Performance report due seven days post-send

    Brands almost always want more than the email. If your initial pitch was “sponsored newsletter slot,” expect the brief to bundle in at least one social amplification requirement. Budget accordingly—those extra deliverables take time, and the fee rarely adjusts upward to match.

    The due dates are usually staggered. The email might be due August 28, but the social posts often have a “within 72 hours of email send” clause. That means you’re not done on send day.

    Messaging guidelines and the red-pen test

    This section tells you what to say—and what you can’t. You’ll see:

    • Required talking points (“emphasize ease of setup”)
    • Prohibited comparisons (“do not mention [Competitor A] or [Competitor B] by name”)
    • Mandatory disclosures (FTC compliance language, sometimes pre-written)
    • Tone guidance (“conversational, not salesy”—ironic, given the constraints)

    The tighter the guidelines, the less the content will sound like you. If a brand sends you three full paragraphs of pre-written copy and asks you to “adapt it to your voice,” you’re ghostwriting their ad, not creating sponsored content. That’s fine if the price reflects it, but a $1,500 fee for what amounts to light editing is low.

    Some operators push back here. If the brief leaves you fewer than 200 words of original writing in a 600-word piece, ask for either a higher fee or more creative latitude. Brands used to working with larger creators are often flexible; performance marketing teams less so.

    Exclusivity windows and category blocks

    Buried mid-brief, you’ll find the exclusivity clause. It typically reads: “Creator agrees not to promote competing products in the [category] for [30/60/90] days before or after this campaign.”

    If you run a newsletter about productivity tools and you sign a 60-day exclusivity window for a task manager sponsor, you’ve just locked yourself out of promoting any other task manager—including affiliate links—for four months. That’s fine if this sponsor pays enough to replace that affiliate revenue. It’s not fine if you didn’t notice the clause until after you signed.

    Watch for category definitions. A “project management tool” exclusivity clause might be interpreted by the brand to include time trackers, note apps, or even calendar tools. Get the category scope in writing. If the brand says “we mean direct competitors only,” ask them to list those competitors by name in the brief.

    Usage rights and reshare permissions

    The final section covers what the brand can do with your content after you publish it. Common clauses:

    • Perpetual right to reshare the content on brand-owned channels
    • Permission to edit for length (social clips, pull quotes)
    • Inclusion in paid media (your face in their Facebook ads)
    • White-label rights (republishing with attribution removed)

    Most operators accept resharing and light editing. Paid media inclusion should come with a separate fee—your likeness in their ad campaign is worth more than a single sponsored post rate. White-label clauses are rare, but they exist; push back hard unless the fee is 3–5× your normal rate.

    If the brief is silent on usage rights, clarify in writing before you publish. Default assumptions vary by industry. SaaS brands usually assume they can reshare excerpts; agencies sometimes assume they own the entire asset.

    What to do before you countersign

    Read the brief twice. Once for deliverables and price, once for constraints and rights. If any section is vague—especially exclusivity, usage rights, or revision limits—reply with clarifying questions before you agree. Brands expect this. The ones that don’t aren’t worth working with.

    Keep a simple checklist: Does the scope match what we discussed? Is the exclusivity window acceptable given my other revenue streams? Are the due dates realistic? Do I retain enough creative control that this will still sound like my work?

    If the answer to any of those is no, send a redline. Most brands would rather negotiate than start over with another creator.

    Got a sponsorship question that isn’t covered here? Reply to this email—we’re collecting operator questions for an upcoming Q&A piece.

  • WordPress multisite subdomain DNS: how wildcard records actually work

    WordPress multisite in subdomain mode lets you spin up site1.example.com, site2.example.com, and so on—all from a single WordPress install. It’s powerful for niche site portfolios, client networks, or SaaS-style content platforms. But the DNS setup trips up even experienced operators, especially when subdomains don’t resolve or SSL certificates fail to provision.

    Here’s how the wildcard DNS record actually works, what propagation looks like in practice, and the edge cases that break automated SSL issuance.

    What the wildcard A record does

    When you configure WordPress multisite in subdomain mode, you add a single DNS record at your registrar or DNS provider:

    *.example.com A 203.0.113.45

    That asterisk is a wildcard. It tells DNS resolvers: “any subdomain that doesn’t have its own explicit record should point to this IP address.” So blog.example.com, shop.example.com, and anythingyouwant.example.com all resolve to the same server—your WordPress host.

    The WordPress application then inspects the Host header in each HTTP request and serves the correct site from its internal database. The DNS layer doesn’t know or care which subdomains exist; it just routes everything to the same place.

    Propagation timing and the root domain exception

    Wildcard DNS propagates like any other record—typically within minutes to a few hours, depending on TTL and resolver caching. But two gotchas appear frequently:

    The root domain doesn’t match the wildcard. If you have an existing A record for example.com pointing to a different IP (say, a marketing site on a separate host), that takes precedence. The wildcard only catches subdomains. If you want example.com itself to serve a multisite network site, you need a separate A record for the root, and it must point to the same IP as the wildcard.

    Explicit subdomain records override the wildcard. If you previously set up mail.example.com A 198.51.100.10 for an email service, that record wins. The wildcard only applies when no more-specific record exists. Audit your DNS zone file before enabling multisite—old staging subdomains or forgotten services can create confusing “site not found” errors.

    SSL certificate provisioning and wildcard complications

    Most managed WordPress hosts and CDNs (Cloudflare, Kinsta, WP Engine) offer automatic Let’s Encrypt SSL. But wildcard certificates require DNS-01 challenge validation, not the simpler HTTP-01 method.

    Here’s what that means in practice:

    • Single-site certificates use HTTP-01: Let’s Encrypt places a file at example.com/.well-known/acme-challenge/token, retrieves it, and issues the cert. Takes seconds.
    • Wildcard certificates use DNS-01: Let’s Encrypt asks you to create a TXT record at _acme-challenge.example.com, waits for propagation, validates it, then issues. This requires API access to your DNS provider, which not all hosts support automatically.

    If your host doesn’t support wildcard SSL automation, you have two options:

    1. Manually provision wildcard certs every 90 days (painful).
    2. Use a reverse proxy like Cloudflare in front of WordPress, letting Cloudflare handle wildcard SSL termination. Traffic flows: visitor → Cloudflare (SSL) → origin server (can be HTTP or a Cloudflare-issued origin cert).

    Cloudflare’s free tier includes wildcard SSL and works well for multisite operators who don’t need enterprise SLA guarantees. Just ensure SSL/TLS mode is set to “Full” or “Full (strict)”—”Flexible” mode (Cloudflare-to-visitor encrypted, Cloudflare-to-origin unencrypted) creates mixed-content warnings and breaks WordPress admin over HTTPS.

    When new subsites don’t resolve immediately

    You create a new subsite in WordPress, visit newsite.example.com, and get a DNS error. The wildcard’s already in place—what’s wrong?

    Two common causes:

    Local DNS cache. Your machine or router cached a previous NXDOMAIN (non-existent domain) response. Flush your local DNS cache (sudo dscacheutil -flushcache on macOS, ipconfig /flushdns on Windows) or wait 5–15 minutes.

    CAA records blocking SSL issuance. If you have a CAA record at the root domain restricting which certificate authorities can issue certs (e.g., example.com CAA 0 issue "letsencrypt.org"), and your host uses a different CA or expects wildcard issuance, the cert request fails silently. Check your DNS zone for CAA records if SSL won’t provision for new subsites.

    One non-obvious tip: use a staging wildcard on a separate domain

    If you’re testing multisite before going live, don’t use a subdomain of your production domain—use a completely separate domain or a .test suffix with local /etc/hosts entries. Why? Because once you add the wildcard A record to your live domain, every possible subdomain resolves, including ones you haven’t created yet. That can expose staging sites to search engines or curious visitors poking around common subdomain names like staging.example.com or dev.example.com.

    A safer pattern: register example-staging.com, apply the wildcard there, and test your network in isolation. When ready, migrate to the production domain with confidence that DNS and SSL won’t surprise you.

    Got a WordPress multisite setup question? Hit reply—we’d love to feature your scenario in a future Q&A piece.

  • Traffic attribution windows: 1-day vs. 7-day vs. 30-day click

    Traffic attribution windows: 1-day vs. 7-day vs. 30-day click

    Traffic attribution windows: 1-day vs. 7-day vs. 30-day click
    Photo by Frank Rolando Romero on Unsplash

    Attribution windows control how long a click gets credit for a conversion. A visitor clicks your Facebook ad today, signs up tomorrow—does the ad get credit? That depends on your window setting.

    Most platforms default to 7-day click attribution. Google Ads, Facebook Ads Manager, and analytics tools treat this as the standard. But 1-day and 30-day windows exist for good reasons, and picking the wrong one skews your entire acquisition strategy.

    What each window measures

    A 1-day click window credits conversions that happen within 24 hours of the click. It favors high-intent traffic—people who click and convert immediately. If you run retargeting ads or promote time-sensitive offers, 1-day attribution isolates fast movers. It also deflates your reported conversion rate, because anyone who takes two days to decide doesn’t count.

    A 7-day click window stretches the timeline to a week. This captures people who click, bookmark, think it over, then come back and subscribe or buy. Most B2C purchases and newsletter signups fall inside seven days. It’s why this is the default: it balances immediacy with realistic decision cycles.

    A 30-day click window credits conversions up to a month after the click. This favors long consideration cycles—B2B SaaS trials, high-ticket courses, consulting services. If your average customer reads three blog posts and downloads a lead magnet before buying, 30-day windows give you a fuller picture. The downside: they inflate attribution for channels that generate early awareness but don’t close the sale.

    When short windows hide channel value

    If you run cold traffic campaigns—SEO blog posts, YouTube tutorials, LinkedIn thought leadership—1-day windows will make those channels look terrible. Someone discovers your site via Google, reads two posts, subscribes to your newsletter three days later. A 1-day window credits nothing. A 7-day window credits the blog post. A 30-day window credits it plus any other touchpoint in the prior month.

    This is why content marketers and SEO operators prefer longer windows. Content rarely converts same-day. If you judge an SEO article by 1-day attribution, you’ll kill posts that actually seed your funnel.

    Conversely, if you run retargeting ads or flash sales, 7-day and 30-day windows give credit to clicks that didn’t matter. Someone clicked your carousel ad two weeks ago, forgot about it, then found you via organic search and subscribed. The 30-day window credits the ad. The 1-day window credits nothing, because the real driver was search.

    Platform defaults and where they diverge

    Google Ads defaults to 30-day click attribution for conversions. Facebook Ads Manager defaults to 7-day click, 1-day view. Google Analytics 4 lets you set attribution windows per conversion event, but defaults to 90 days for some goals and 30 for others, depending on how you configured them.

    If you’re comparing Facebook CPM to Google Search CPC, and Facebook reports conversions on a 7-day window while Google uses 30, you’re not comparing the same metric. Facebook looks cheaper because fewer conversions qualify. Normalize the windows before you shift budget.

    Stripe and payment processors don’t use attribution windows—they timestamp purchases. If you’re reconciling ad spend to revenue, you need to apply the window logic yourself. Export clicks by date, exports conversions by date, match them within your chosen window, then calculate cost per acquisition. Most operators skip this step and wonder why dashboard revenue doesn’t match bank deposits.

    How to pick your window

    Start with your median time-to-conversion. If 80% of your newsletter subscribers sign up within 48 hours of first visit, a 7-day window is fine. If 60% of your course buyers take two weeks to decide, use 30 days.

    Run a simple query: pull your conversion events (signups, purchases, trial starts) and join them to first-touch timestamps. Calculate the gap. If the 75th percentile is under seven days, a 7-day window won’t lose much signal. If it’s over two weeks, you need 30.

    For operators running multiple channels, set different windows per channel in your spreadsheet or BI tool, even if the platform won’t let you. Tag SEO traffic with a 30-day window, tag retargeting with 1-day, then compare them honestly. You’ll stop over-investing in channels that look good under long windows but don’t actually close.

    One more thing: if you change your attribution window mid-campaign, your before/after metrics aren’t comparable. Conversion rate, CPA, and ROAS all shift when you change the counting rule. Document the switch, split your reporting periods, and don’t blend the data.

    Want more breakdowns like this? Subscribe to One Two Three Send for weekly deep-dives on the tools, metrics, and workflows that actually matter for online operators.

  • AI prompt libraries: when saving templates costs more than rewriting

    AI prompt libraries: when saving templates costs more than rewriting

    AI prompt libraries: when saving templates costs more than rewriting
    Photo: Ginny from USA via Wikimedia Commons (CC BY-SA 2.0)

    Most solo operators start saving AI prompts the moment they get a good output. A Notion database here, a text file there, maybe a dedicated prompt-management SaaS tool. The logic is sound: if a prompt worked once, save it and reuse it.

    But six months in, something shifts. You open your prompt library, copy a saved template, paste it into Claude or ChatGPT, and the output is… wrong. Not catastrophically bad, just off. The tone doesn’t match your current voice. The structure assumes a product feature you deprecated. The examples reference a pricing model you changed in March.

    You spend twelve minutes editing the prompt, testing it, and tweaking the output. Writing from scratch would have taken eight.

    The hidden cost of prompt drift

    Prompts aren’t like code snippets. A function that sorts an array will sort an array forever. But a prompt that generated a great welcome email in January 2026 assumes the context, audience, and product state of January 2026.

    When any of those variables change—your positioning tightens, your audience skews more technical, you add a new tier—the saved prompt becomes subtly misaligned. You don’t notice immediately because the output is plausible. It’s only after you ship it, or read it twice, that you realize it doesn’t quite fit.

    The problem compounds when you save dozens of prompts. Each one is a snapshot of a moment in time. Unless you version them, tag them with context, or add timestamps and notes about what was true when you wrote them, you’re maintaining a library of decaying artifacts.

    When prompt libraries actually work

    There are situations where saving prompts makes sense:

    • Highly repetitive, low-context tasks. If you’re generating meta descriptions for product pages with identical structure, a template works. The input variables (product name, key feature) are stable, and the output format never changes.
    • Prompts with complex, non-obvious structure. If you’ve built a multi-step prompt chain with specific XML tags, conditional logic, or output formatting that took an hour to debug, save it. The setup cost is high enough that rewriting isn’t faster.
    • Team handoffs. If you’re delegating a task to a VA or contractor, a saved prompt with usage notes ensures consistency. You’re not optimizing for speed—you’re optimizing for replicability.

    For everything else—blog intros, email rewrites, social captions, brainstorming lists—the overhead of maintaining a library often exceeds the time saved by reusing a prompt.

    What to do instead

    Most operators don’t need a prompt library. They need a prompt framework—a mental model for constructing prompts on the fly.

    Instead of saving fifty variations of “write a LinkedIn post,” save a three-part structure: role + task + constraints. When you need a LinkedIn post, you reconstruct it in fifteen seconds: “You’re a SaaS founder writing for other founders. Write a 150-word LinkedIn post about why we switched from Stripe to Lemon Squeezy. Casual tone, no hashtags.”

    The framework is portable. It adapts to your current context because you’re generating the prompt, not retrieving it.

    If you do save prompts, treat them like code: version them, add comments, and archive anything older than three months unless you’ve actively used it. A prompt you haven’t touched since March is probably not worth keeping.

    The exception: Claude Projects

    If you’re using Claude’s Projects feature, the calculus changes slightly. Projects let you attach context documents—style guides, product specs, audience notes—that persist across chats. That context is reusable without the drift problem, because it’s modular. You update the style guide once, and every prompt in that project inherits the change.

    But even then, the prompts themselves should be ephemeral. The context is what you’re saving, not the exact wording of every request.

    Most solo operators are over-indexed on saving prompts and under-indexed on refining their ability to write them quickly. The goal isn’t a library of perfect prompts. It’s the skill to generate a good-enough prompt in thirty seconds, every time.

    Want more operator tactics like this? Subscribe to One Two Three Send—one article daily, no fluff, no affiliate spam unless the tool actually fits.

    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.

  • Newsletter A/B tests resolve slower than you think—here’s the lag

    Newsletter A/B tests resolve slower than you think—here’s the lag

    Newsletter A/B tests resolve slower than you think—here's the lag
    Photo by Markus Winkler on Unsplash

    You send an A/B test at 9 a.m. By noon, variant B has a 4% higher open rate than A. You declare a winner, stop the test, and send B to the rest of your list.

    You just made a decision on incomplete data—and probably picked the wrong winner.

    Newsletter A/B tests don’t resolve in real time. Most platforms need 24 to 48 hours of data before statistical significance kicks in. Open rates stabilize slowly, click rates lag further, and early leads often reverse as time zones wake up and inbox behavior shifts throughout the day.

    Why early results mislead

    Email opens don’t happen all at once. The first hour skews toward your most engaged subscribers—people who check email immediately, often on mobile. That audience behaves differently from the median subscriber who opens your email six hours later, or the next morning.

    If variant B uses a curiosity-gap subject line (“You won’t believe…”) and variant A is descriptive, B will likely win in the first two hours. Curiosity hooks grab attention fast. But descriptive lines often perform better over 24 hours because they set accurate expectations and attract clicks from readers who actually want the content.

    Click rates take even longer to stabilize. Opens happen within minutes; clicks happen after reading. If your test measures clicks, you need at least 24 hours. If you’re testing send-time optimization or different audience segments, 48 hours is safer.

    ConvertKit and Beehiiv both recommend waiting 24 hours before evaluating A/B test results. MailerLite’s documentation suggests 48 hours for click-based tests. Postmark doesn’t offer built-in A/B testing—it’s designed for transactional mail—but their support team advises the same window when operators run manual split tests using tags.

    Statistical significance isn’t a progress bar

    Most platforms show a confidence percentage or a “statistical significance” badge. That number updates in real time, but it doesn’t mean what you think it does.

    A 95% confidence score after two hours doesn’t guarantee variant B is the true winner. It means that if the current pattern holds, there’s a 95% chance B is better. But the pattern rarely holds. Early openers are not representative of your full list.

    Platforms calculate significance using sample size and effect size. Small lists hit significance faster, but they’re also more vulnerable to noise. If you have 1,000 subscribers and variant B gets 10 extra opens in the first hour, that might push confidence above 90%—but it’s not stable.

    Larger lists take longer to resolve but produce more reliable results. A 50,000-subscriber test might take 36 hours to hit 95% confidence, but when it does, the winner is far more likely to hold.

    The refresh trap

    Refreshing your analytics dashboard every hour doesn’t speed up the test. It increases the odds you’ll stop early and pick a false winner.

    This isn’t unique to newsletters. A/B testing in any channel—landing pages, ad creative, checkout flows—requires patience. But email has a specific temporal curve that makes early data especially unreliable. Inbox providers throttle delivery. Time zones stagger opens. Engagement drops off after 48 hours for most lists, so the meaningful window is narrow.

    If you’re testing subject lines, wait 24 hours. If you’re testing content, layout, or CTAs, wait 48. If your list is under 5,000 subscribers, add another 12 hours—small sample sizes need more time to smooth out variance.

    When to end a test manually

    Sometimes you need to stop early. If one variant has a 60% open rate and the other has 12%, and you’re six hours in with 2,000 opens, the test is over. Catastrophic failure is obvious.

    But if the gap is 23% vs. 27%, or one variant leads by 30 clicks out of 8,000 sends, let it run. Small edges flip constantly in the first 12 hours.

    Set your test duration when you launch it, then ignore the dashboard until the timer runs out. Most platforms let you configure this in advance—ConvertKit and Beehiiv both allow you to set a fixed test window and auto-send the winner after X hours. Use that feature. It removes the temptation to call it early.

    Want sharper sends? Reply with the A/B test you’re running this week—I’ll tell you if you’re measuring the right thing.

    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.

  • Instagram alt-text editing: how it works after you publish

    Instagram alt-text editing: how it works after you publish

    Instagram alt-text editing: how it works after you publish
    Photo: Agência Senado from Brasilia, Brazil via Wikimedia Commons (CC BY 2.0)

    Instagram lets you add alt text to every post, Reel, and Story image. Most operators either skip it entirely or fill it in once during upload and forget it exists. What fewer people realize: you can edit alt text after publication—and there are real reasons to do it.

    If you’re running a content-driven business on Instagram, alt text isn’t just an accessibility feature. It’s indexable metadata that can surface your posts in search, and it’s a second chance to clarify context when a caption doesn’t tell the full story.

    How to edit alt text after you’ve published

    Open the post. Tap the three-dot menu in the top right. Select Edit. At the bottom of the screen (below the caption field), you’ll see Advanced Settings. Tap it. Scroll down to Alt Text. Tap Write Alt Text, edit the field, and save.

    The interface hasn’t changed much since Instagram added manual alt text in 2018, but it’s still buried two taps deeper than caption editing. That’s deliberate—Instagram auto-generates alt text using object recognition, and most users never touch it.

    For operators, though, the auto-generated version is almost always too generic. A product photo might get tagged as “image may contain: indoor, table, object” when what you actually posted was a course workbook mockup on a desk. The difference matters for search discoverability and for screen-reader users.

    When to go back and edit alt text

    Three scenarios where editing after publication makes sense:

    You published in a rush and skipped it. Common when you’re posting from mobile during a launch or event. Circle back within 24 hours—Instagram’s ranking window for Explore and hashtag feeds is short, but search indexing is ongoing.

    The post is evergreen and still getting impressions weeks later. If a carousel or single image keeps showing up in your top posts by reach, adding better alt text can extend its shelf life in search. Check your Instagram Insights for posts with long tails—anything still pulling 100+ impressions per week after 30 days is worth revisiting.

    You’re repurposing content across platforms and want consistent metadata. If you cross-post to Facebook (which shares alt text fields), Pinterest, or LinkedIn, editing Instagram’s alt text keeps your asset library uniform. Especially useful if you’re using a scheduler like Publer that can carry alt text forward into future posts.

    One non-obvious gotcha

    Instagram doesn’t timestamp alt text edits, and it doesn’t notify followers when you change it. That sounds convenient—no “edited” label like you get on captions—but it creates a tracking problem.

    If you’re running tests (say, comparing generic vs. descriptive alt text on product posts), you can’t tell from the Instagram app when you made the change. The edit is invisible in your activity log. If you’re A/B testing alt text impact on reach, you need to log the change externally—spreadsheet, notes app, or a dedicated social media tracker.

    This also means you can’t reverse-engineer what alt text a competitor used if they’ve edited it. You only see the current version. If you’re researching how other operators optimize for Instagram search, screenshot the alt text the first time you see a post, because it might not be there next week.

    What to write (and what to skip)

    Alt text should describe what’s in the image, not repeat your caption. Instagram’s guidance says 100 characters or fewer, but the field accepts up to 300. Screen readers handle long alt text fine, but search indexing seems to weight the first 100–125 characters more heavily based on anecdotal testing from accessibility-focused operators.

    Skip hashtags, emojis, and brand slogans. Don’t write “Photo of…” or “Image shows…”—screen readers already announce it’s an image. Just describe it: “Laptop on desk with coffee mug and open notebook” beats “Image may contain: electronics, beverage, indoor.”

    If the image contains text (quote graphic, announcement, tutorial screenshot), transcribe the key text in the alt field. Instagram’s auto-recognition doesn’t do OCR reliably, so “Launch day: 300 subscribers in 48 hours” is better alt text than “text, screenshot.”

    For carousels, you write separate alt text for each image. Tap into edit mode, swipe to the image you want to describe, open Advanced Settings, and write the alt text for that slide. It’s tedious for 10-slide carousels, but if you’re repurposing a carousel as a lead magnet or using it in ads later, front-loading that work pays off.

    Does it actually affect reach?

    Instagram has never confirmed that alt text is a ranking signal for Explore or hashtag feeds. But it’s confirmed that alt text feeds into search—both the general search bar and the newer keyword search that rolled out in 2024. If someone searches “newsletter dashboard screenshot” and your alt text says exactly that, you have a better shot at surfacing than if Instagram auto-tagged it as “screenshot, text, computer.”

    Anecdotally, operators who’ve back-filled alt text on 50+ evergreen posts report small upticks in profile visits from search—5–10% over 60 days. Not explosive, but enough to make it worth 15 minutes of cleanup work.

    More importantly, it’s a file-keeping habit that saves time later. If you ever export your Instagram content (for a portfolio, a website gallery, or a course), having real alt text instead of auto-generated garbage makes the migration cleaner.

    Want this in your inbox? One Two Three Send breaks down one tool, tactic, or workflow decision every day—no fluff, just what works for operators running online businesses. Subscribe at the top of the page.

    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.

  • Productivity workflow automation: when triggers fire twice

    Productivity workflow automation: when triggers fire twice

    Productivity workflow automation: when triggers fire twice
    Photo by Sasun Bughdaryan on Unsplash

    You set up a Zapier workflow to save new Stripe customers into your CRM. Two hours later, you’ve got 14 duplicate contacts and three confused replies from customers who received the same welcome email twice.

    Automation platforms let you wire together dozens of tools without writing code, but they rarely warn you when two triggers point at the same event. The result: workflows that fire twice, charge twice, or create phantom records you’ll spend hours cleaning up.

    Here’s how to spot the problem before it compounds, and what to do when you’ve already built a mess.

    Why triggers fire more than once

    Most automation platforms treat every integration as stateless. They don’t know—or care—if another workflow is already watching the same event. If you build one Zap that triggers on “new Stripe payment” and another that triggers on “new Stripe customer,” both will fire when someone buys for the first time. Same payment, two workflows, double the side effects.

    The overlap gets worse when you use multi-step platforms. A workflow might trigger on “new ConvertKit subscriber,” add them to a Google Sheet, then use that sheet row as a trigger for a second workflow. If the sheet-update step retries due to a rate limit or API timeout, the second workflow fires again.

    Webhook-based triggers are even messier. If your endpoint returns a 500 error, most platforms retry the webhook three to five times over the next hour. Each retry can spawn a new workflow run unless you’ve implemented idempotency checks—and most solo operators haven’t.

    Where to look for duplicate triggers

    Open your automation platform and list every active workflow. Group them by trigger type: “new email subscriber,” “payment received,” “form submitted,” “spreadsheet row added.” If two workflows share the same trigger event but act on different downstream steps, you’ve got overlap risk.

    Check your CRM, spreadsheet, or database for duplicate records created within seconds of each other. Sort by timestamp. If you see the same email address, order ID, or name appearing twice with a five-second gap, you’re looking at a double-trigger.

    Look at your email logs. Platforms like Postmark and Brevo show you every message sent, including duplicates. If a single transaction triggered two identical emails, trace backward to the workflow that sent them.

    Review your payment processor’s event log. Stripe, Lemon Squeezy, and PayPal all timestamp webhook deliveries. If you see the same charge.succeeded event delivered twice to your automation platform, and both deliveries returned HTTP 200, the fault is in your workflow logic—not the webhook.

    How to fix it without rebuilding everything

    Add a deduplication step at the start of every workflow. Most platforms let you query a database or spreadsheet to check if a record already exists. In Zapier, use a “Lookup Spreadsheet Row” or “Find Record” action before you create anything new. If the lookup returns a match, stop the workflow.

    Use a dedicated idempotency table. Create a Google Sheet or Airtable base with two columns: event ID and timestamp. Every time a workflow starts, write the trigger’s unique ID (Stripe charge ID, form submission ID, ConvertKit subscriber ID) to the table. Before processing, check if that ID already exists. If it does, halt.

    Switch from polling-based triggers to webhook triggers where possible. Polling checks for new data every 5 or 15 minutes and can catch the same record multiple times if your workflow is slow. Webhooks fire once per event and include a unique event ID you can store and check.

    Set up error alerts that fire before your workflow completes. If a step fails halfway through, you want to know immediately—not after the platform retries and creates duplicates. Zapier, Make, and n8n all support email or Slack notifications on step failure.

    When to split workflows vs. merge them

    If two workflows handle different outcomes from the same trigger, merge them into a single workflow with conditional branches. Instead of one Zap for “new paying customer” and another for “new free trial signup,” build one workflow that checks the payment amount and branches accordingly.

    If your workflows act on truly separate events—new blog post published vs. new email subscriber—keep them separate. The risk of duplicate triggers is low, and merging adds complexity you don’t need.

    When a workflow grows past eight steps, consider splitting it. Long workflows are harder to debug, and a failure in step six means steps one through five run again on retry. Break complex automations into smaller workflows connected by a shared data store, and add idempotency checks at every entry point.

    Want more workflow breakdowns like this? Subscribe to One Two Three Send for operator-focused guides every week—no fluff, just the automation logic that saves you hours and prevents expensive mistakes.

    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.

  • Analytics custom dashboards: when pre-built templates mislead you

    Analytics custom dashboards: when pre-built templates mislead you

    Analytics custom dashboards: when pre-built templates mislead you
    Photo by Stephen Phillips – Hostreviews.co.uk on Unsplash

    Most analytics platforms ship with attractive templates. You connect your data source, the dashboard populates itself, and you get a grid of charts that look professional enough to screenshot for a board deck.

    The problem: those templates measure what the vendor thinks matters, not what actually drives your business. And because they look polished, operators assume they’re looking at the right metrics—until revenue stalls and the dashboard still shows green.

    What pre-built dashboards optimise for

    Analytics vendors design default templates to serve the widest possible audience. That means they prioritise:

    • Vanity metrics that trend upward. Page views, session counts, total subscribers. These make new users feel good and reduce churn during trial periods.
    • Metrics that showcase platform features. If the tool sells attribution modelling, the dashboard will surface multi-touch funnels—even if you’re a solo operator with one traffic source.
    • Industry averages that may not apply. E-commerce dashboards assume you care about cart abandonment rate. But if you sell a $2,000 course with a multi-week consideration cycle, cart behaviour is noise.

    The result: you spend every Monday morning reviewing a dashboard that tells you visits are up 12% but can’t explain why revenue per subscriber dropped.

    The metrics that actually matter depend on your model

    If you run a sponsored newsletter, your core dashboard should answer:

    • What’s my seven-day open rate by acquisition source?
    • Which posts drove the most sponsor link clicks?
    • What’s my subscriber-to-sponsor-ready ratio? (Sponsors care about engaged readers, not total list size.)

    If you sell a productised service with monthly retainers, you need:

    • Monthly recurring revenue vs. one-time project income.
    • Client lifetime value by acquisition channel.
    • Churn rate and leading indicators (missed payments, support ticket volume).

    If you monetise with affiliates and ad networks, track:

    • Revenue per thousand visitors by content category.
    • Affiliate conversion rate by product and placement.
    • Traffic source profitability after paid acquisition cost.

    None of these maps cleanly onto a Google Analytics 4 or Plausible default template. You have to build it yourself.

    When to abandon the template and start from scratch

    Here’s the test: open your current dashboard and ask, “If this metric moved 20% in either direction, would I change what I do this week?”

    If the answer is no, delete the widget.

    Then list the three business questions you asked yourself in the last 30 days. Examples:

    • “Why did last week’s post convert worse than the week before?”
    • “Which traffic source sends readers who actually buy?”
    • “Is my welcome sequence still working, or has open rate decayed?”

    Build one dashboard widget per question. If your analytics platform can’t answer it, you’re either tracking the wrong events or using the wrong tool.

    What good custom dashboards look like

    Effective operator dashboards are not beautiful. They’re a small grid—often just four to six widgets—that update weekly and drive a specific decision.

    A working example from a course creator I consulted for:

    • Widget 1: Revenue this month vs. same month last year.
    • Widget 2: Email-to-purchase conversion rate for the last four launches.
    • Widget 3: Refund rate by cohort (tracks product-market fit over time).
    • Widget 4: Traffic source breakdown for purchase-page visitors (not all visitors).

    That’s it. Four numbers. Every Monday, she knows whether to focus on traffic, conversion, or retention. The default Stripe dashboard showed gross volume and successful charges—impressive numbers that didn’t clarify what to do next.

    One dashboard, one decision

    If you’re still using a pre-built template, block an hour this week to rebuild from scratch. Start with one business question. Add only the metrics that answer it. If you can’t connect a widget to a decision you’ll make in the next 30 days, leave it out.

    The goal isn’t a dashboard that impresses a investor. It’s a dashboard that tells you what to do on Tuesday.

    What’s the one metric you check every week that actually changes how you work? Hit reply and tell me—I’m collecting examples for a deeper dive on operator-specific analytics setups.