Author: onetwothreeadmin

  • Traffic source tagging: when UTM parameters break your funnel

    Traffic source tagging: when UTM parameters break your funnel

    Traffic source tagging: when UTM parameters break your funnel
    Photo: Ajiro Shinpei via Wikimedia Commons (CC BY-SA 4.0)

    UTM parameters are the standard way to tag inbound traffic. You append ?utm_source=twitter&utm_medium=social&utm_campaign=launch to a URL, and your analytics platform tells you exactly where visitors came from.

    Except when they don’t. Or when they tell you too much. Or when the tags themselves break the thing you’re trying to measure.

    Most operators treat UTM tagging as a best practice with no downsides. But tagging everything creates three specific problems that can corrupt your funnel data, kill affiliate commissions, and fragment user sessions in ways that make attribution worse, not better.

    Problem one: UTM parameters create new sessions

    Google Analytics 4 treats each unique UTM combination as a new traffic source. If a visitor lands on your site from an organic search, then clicks a UTM-tagged link in your own newsletter five minutes later, GA4 records two separate sessions with two different sources.

    This matters when you’re measuring time-to-conversion or return-visitor behavior. A subscriber who clicks three different UTM-tagged links in three emails over two weeks shows up as three separate users in your funnel reports. Your email conversion rate looks lower than it is, and your session duration gets artificially shortened every time someone re-enters via a tagged link.

    The fix: don’t use UTM tags on internal links—emails to your own subscribers, in-app notifications, or links between pages on your own domain. Use GA4’s built-in email campaign tracking instead, or tag only the first entry point (e.g., a landing page) and let internal navigation remain untagged.

    Problem two: tagged URLs break affiliate cookie attribution

    Most affiliate programs set a tracking cookie when someone clicks your referral link. That cookie persists for 30, 60, or 90 days, so you get credit even if the visitor returns later to purchase.

    But some affiliate platforms treat any URL with query parameters—including UTM tags—as a distinct destination. If you link to example.com/product?via=yourID&utm_source=newsletter, the affiliate platform may fail to recognize the destination URL, drop the cookie, or attribute the sale to someone else.

    Amazon Associates is particularly strict about this. Their link structure already includes tracking parameters, and appending UTMs can invalidate the referral. The sale still happens, but you don’t get credited.

    The workaround: test every tagged affiliate link in a private browser session before you send it. Clear cookies, click the link, and verify that the affiliate platform sets its tracking cookie. If it doesn’t, remove the UTM tags or use a redirect service that strips parameters after the cookie is set.

    Problem three: over-tagging fragments your source reports

    If you tag every social post, every email, and every ad with unique campaign names, your traffic source report becomes unreadable. Instead of seeing “newsletter traffic converts at 8%,” you see forty rows: one for each individual send, each with too few conversions to be statistically meaningful.

    This is especially common with automated tagging tools that append timestamps or post IDs to campaign parameters. You end up with utm_campaign=launch_email_20260904_v2 instead of just utm_campaign=launch, and every report requires manual grouping to be useful.

    The solution: use a consistent naming taxonomy. Limit utm_campaign to high-level initiatives (product launch, seasonal promo, onboarding series). Use utm_content or utm_term for granular variation tracking, and set up GA4 custom channel groups or BigQuery exports if you need to analyze individual sends.

    When UTM tagging actually helps

    UTM parameters are still the best tool for tracking external traffic sources that don’t pass referrer data: social media platforms, messaging apps, QR codes, and anywhere you can’t rely on the HTTP referer header.

    They’re also essential for paid campaigns where the ad platform doesn’t automatically pass source information, and for any A/B test where you’re comparing different traffic sources or creative variations.

    The rule: tag external traffic and high-value experiments. Skip internal links, test affiliate compatibility before sending, and keep your campaign taxonomy simple enough to read six months from now.

    Got a question about tagging, attribution, or analytics setup? Reply to this email—we’ll cover it in a future issue.

  • AI prompt versioning: when to save, fork, or start fresh

    AI prompt versioning: when to save, fork, or start fresh

    AI prompt versioning: when to save, fork, or start fresh
    Photo by Prayag Tejwani on Unsplash

    If you’re using AI assistants daily, you’ve hit the moment: a prompt that worked last week suddenly feels stale. You tweak a line. Then another. Twenty minutes later, you’re staring at a Frankenstein instruction set that produces worse output than your original—and you didn’t save the version that worked.

    Prompt versioning sounds like overkill until you need it. Most solo operators don’t version their prompts at all. A handful save everything obsessively. The right answer sits between those extremes, and it depends on what kind of prompt you’re working with.

    Three prompt types, three versioning strategies

    One-off exploratory prompts: Don’t save these. If you’re drafting a single social post, testing an outline format, or asking a research question, there’s no ROI in versioning. You’ll never reuse the exact phrasing. Let it live in your chat history and move on.

    Templated repeatable prompts: Save a canonical version, but don’t track every edit. These are prompts you run weekly—email subject line generators, product description templates, summary boilerplate. Keep one master copy in a note or doc. When you improve it, overwrite the old version. You don’t need a change log; you need a reliable starting point.

    High-stakes or multi-person prompts: Version these properly. If a prompt controls brand voice across a team, generates customer-facing content at scale, or took hours to tune, treat it like code. Save dated versions. Label what changed and why. Use a simple naming convention: email-outline-v3-2026-09-04 works fine. You’re not trying to impress a GitHub contributor; you’re protecting your ability to roll back when an edit breaks output quality.

    When to fork instead of edit

    Forking means duplicating a prompt and modifying the copy, leaving the original intact. Do this when you want to test a structural change but aren’t sure it’ll work. Examples: switching from bullet output to paragraph form, adding a new constraint that might conflict with existing instructions, or adapting a B2C prompt for B2B use.

    If the fork works, you now have two specialist prompts instead of one generalist. If it doesn’t, you delete it and keep the original. This is cheaper than A/B testing in production or wondering why your reliable prompt suddenly underperforms.

    What actually matters in a version note

    Most version notes are useless. “Updated prompt” tells you nothing. “Improved output quality” is only slightly better. Useful version notes answer one question: what will break if I roll back?

    Good examples:

    • “Added length cap of 280 chars—removes context but fits Twitter.”
    • “Switched from ‘you’ to ‘we’—changes tone from instructional to collaborative.”
    • “Removed brand name from system prompt—now relies on user message to supply it.”

    Each note tells you the trade-off. That’s what you need when you’re deciding whether to revert.

    Where to store versions without overthinking it

    Plain text files work. So do Google Docs with version history enabled. Notion databases let you tag by use case and date. Some operators use Claude Projects to pin multiple prompt versions as context artifacts—useful if you’re iterating inside a single long-running conversation.

    The tool doesn’t matter. What matters is that you can find the last known-good version in under 30 seconds when today’s experiment flops.

    The surprisingly common failure mode

    Here’s what breaks most often: you tune a prompt for weeks, it works beautifully, then the underlying model updates. Your prompt still runs, but output quality drops or formatting changes. You assume your prompt is the problem, so you rewrite it. Now you have a worse prompt and no clean comparison to isolate whether the model or your edits caused the regression.

    Versioning doesn’t prevent model drift, but it lets you test your old prompt against the new model behavior cleanly. If the old version also underperforms now, you know the model changed. If only the new version is bad, you know your edits were the culprit.

    When versioning is just procrastination

    Some operators version everything because it feels productive. It’s not. If you’re spending more time labeling and filing prompts than using them, you’re optimizing the wrong thing. Version control is a loss-prevention tool, not a productivity system. Use it when the cost of losing a prompt exceeds the cost of saving it. For most one-person operations, that threshold is higher than you think.

    If you’re running a content operation that depends on repeatable AI output, start with just two saved versions: the one you’re using now, and the last one that worked. Everything else is optional until it’s not.

    Want more on how solo operators are actually using AI day-to-day—without the hype? Subscribe to One Two Three Send. One focused piece like this, delivered 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.

  • WordPress REST API rate limiting: how plugins enforce request caps

    WordPress REST API rate limiting: how plugins enforce request caps

    WordPress REST API rate limiting: how plugins enforce request caps
    Photo by Stephen Phillips – Hostreviews.co.uk on Unsplash

    If you run a WordPress site with any meaningful traffic—or if you’ve built automation that hits your own API—you’ve probably seen a 429 error at some point. The WordPress REST API doesn’t enforce rate limits by default, but most production sites end up with them anyway, often without realizing it.

    The limits come from security plugins, caching layers, or server-level middleware. They’re rarely documented in dashboards, and they trigger differently depending on whether the request is authenticated, what endpoint you’re hitting, and whether the plugin treats logged-in users differently from unauthenticated bots.

    Here’s how the most common rate-limiting mechanisms actually work, and what to check when legitimate requests start getting blocked.

    Where rate limits come from

    Core WordPress doesn’t rate-limit the REST API. It’s open by default. But most hosting providers and security plugins layer restrictions on top:

    • Security plugins like Wordfence, iThemes Security, and Sucuri impose per-IP request caps, usually between 10 and 60 requests per minute depending on the endpoint.
    • Hosting firewalls (Cloudflare, server-level mod_security rules, or host-specific WAFs) apply blanket limits to all /wp-json/ traffic, often as low as 5 requests per second.
    • Caching plugins (WP Rocket, LiteSpeed Cache) sometimes block repeat API calls as part of bot-protection rules, especially if the requests bypass the cache entirely.

    The problem: these tools don’t coordinate. A single legitimate automation script can trip multiple rate limiters at once, and the error messages rarely tell you which layer rejected the request.

    How plugins enforce caps

    Most WordPress security plugins use one of two methods:

    IP-based throttling: The plugin logs request timestamps per IP address. If you exceed the cap within the time window, it returns a 429 response. This breaks multi-user environments where users share an IP (office networks, VPNs). It also penalizes API clients that batch requests from a single origin.

    Endpoint-specific rules: Some plugins treat /wp-json/wp/v2/posts differently from /wp-json/custom-namespace/endpoint. Public read endpoints often get stricter limits than authenticated write endpoints, under the assumption that bots hammer public routes more aggressively. Wordfence, for example, applies a default 10-request-per-minute cap to unauthenticated API traffic, but allows 60 for logged-in users.

    The gotcha: if your automation uses application passwords or OAuth tokens, the plugin may still treat it as unauthenticated if the token isn’t passed correctly in the Authorization header. That drops you into the stricter bucket.

    What the 429 response doesn’t tell you

    When you hit a rate limit, WordPress returns 429 Too Many Requests. Sometimes you get a Retry-After header; often you don’t. The response body rarely names the plugin or layer that blocked you.

    To diagnose:

    • Check server access logs for the exact timestamp of the 429. If the response came from Apache or Nginx (not PHP), it’s a server-level firewall rule, not a plugin.
    • Temporarily disable security plugins one at a time. If the 429 disappears, you’ve found the source.
    • Look for rate-limit settings in your security plugin’s advanced options. They’re rarely on the main dashboard—Wordfence buries them under “Firewall Options,” iThemes under “Advanced Settings.”

    If you’re using Cloudflare, check the Security Events log. Cloudflare’s “Rate Limiting” rules fire independently of WordPress, and they don’t show up in your WordPress error logs at all.

    When to raise limits (and when not to)

    If you’re hitting limits with your own automation, the fix is straightforward: whitelist your script’s IP or user agent in the security plugin’s settings. Most plugins let you exempt specific IPs or authenticated users from throttling.

    If public traffic is hitting limits, don’t just raise the cap. Rate limits exist to block credential-stuffing attacks and brute-force POST spam. Instead:

    • Cache aggressively. If bots are hammering /wp-json/wp/v2/posts, serve that response from Redis or a CDN edge. The request never hits PHP, so it doesn’t count against your rate limit.
    • Require authentication for write endpoints. If your API accepts user-submitted data, force clients to authenticate. Unauthenticated POST requests should return 401, not 200.
    • Monitor which endpoints get hit. If 90% of your API traffic goes to a single route, that’s either a bot or a misconfigured frontend polling too frequently. Fix the source, not the symptom.

    Testing your own limits

    Most operators don’t know their rate limits until they hit them in production. To test:

    Use a simple loop to hit your API 100 times in 60 seconds. Start with an unauthenticated GET request to /wp-json/wp/v2/posts. Note when the first 429 appears, then repeat with an authenticated request using an application password.

    If the limits differ, your plugin treats auth and non-auth traffic separately. If they’re the same, you’re hitting a server-level cap that doesn’t distinguish between the two.

    Most hosting providers don’t advertise their API rate limits. If you’re on managed WordPress hosting, check the knowledge base or open a ticket. The limit is usually there—it’s just not on the pricing page.

    Want more infrastructure breakdowns like this? Subscribe to One Two Three Send—we dig into the mechanics other newsletters skip.

  • Course completion rates: why 6% isn’t failure

    Course completion rates: why 6% isn’t failure

    Course completion rates: why 6% isn't failure
    Photo by Brett Jordan on Unsplash

    If you’ve launched a course and watched completion rates hover between 5% and 15%, you’re not alone. Industry benchmarks consistently show that most students never finish—and that’s not necessarily a business problem.

    The panic around low completion rates comes from treating courses like books or software: products where usage correlates with satisfaction. But digital courses behave more like gym memberships. People buy the option to transform, not just the content.

    What the numbers actually show

    A 2025 analysis of 47,000 online courses across Teachable, Thinkific, and Kajabi found median completion rates of 8.6%. Courses priced under $50 saw 4–7% completion. Courses over $500 hit 12–18%.

    More telling: refund rates don’t correlate with completion. Courses with 6% completion averaged 2.1% refunds. Courses with 22% completion averaged 2.3% refunds. Students who finish aren’t necessarily happier—they’re just different buyers.

    The metric that does predict revenue? Module-one engagement within 72 hours of purchase. Students who start any lesson in the first three days generate 4.2x more lifetime value through upsells, referrals, and repeat purchases—even if they never finish the original course.

    Where completion actually matters

    Completion rates become important in three scenarios:

    Certification or credential programs. If your course grants a certificate that students need for professional credibility, low completion signals a content or pacing problem. Students aren’t buying optionality—they’re buying proof.

    Cohort-based courses with peer interaction. When the experience depends on group discussion or accountability, dropoff creates a worse experience for finishers. A 40-person cohort that shrinks to six by week three undermines the format.

    Courses that unlock access to a community or tool. If finishing the course is a gateway to a paid membership, low completion throttles your next funnel stage. You’re not just losing engagement—you’re losing pipeline.

    Outside these cases, obsessing over completion distracts from what matters: whether buyers feel they got value relative to what they paid.

    What to optimise instead

    If refunds are low and testimonials are strong, your completion rate is a descriptive stat—not a problem to solve. Focus on these instead:

    First-lesson activation. Send a direct link to Lesson 1 in your purchase confirmation email. Don’t make students hunt through a dashboard. Courses that link directly see 34% higher day-one starts.

    Time-to-value in Module 1. Front-load one quick win in the first 15 minutes. A template, a checklist, a single tactic they can deploy today. Students who extract value early tolerate longer, harder lessons later.

    Segmented upsells based on progress. Students who finish 30% of a course are better candidates for your advanced offer than students who finish 100%. They’re still engaged, still motivated, and haven’t yet experienced transformation fatigue.

    Track completion if you want to understand behaviour. But don’t treat it as a quality signal unless your business model requires it.

    When low completion *is* a red flag

    If completion is under 5% and refund requests cite “not what I expected” or “couldn’t follow,” you have a mismatch problem. Your sales page is attracting the wrong buyers, or your content doesn’t match the promise.

    Run a sample audit: pick ten students who requested refunds and five who completed fewer than two lessons. Email them directly. Ask one question: “What were you hoping this course would do for you?” The answers will show you whether you have a marketing problem or a curriculum problem.

    For most solo operators, though, a 6% completion rate on a $197 course with a 1.8% refund rate isn’t failure. It’s proof you’re selling transformation, not homework.

    What’s your course completion rate, and how do you actually use that number? Hit reply—I’m compiling operator data on what metrics drive course iteration decisions.

  • Analytics event naming: why inconsistency kills your funnel data

    Analytics event naming: why inconsistency kills your funnel data

    Analytics event naming: why inconsistency kills your funnel data
    Photo by 1981 Digital on Unsplash

    You set up event tracking six months ago. It worked. You added Google Analytics 4, maybe Plausible or Fathom, wired up a few conversions, and moved on.

    Now you’re trying to build a funnel report and half your events don’t match. button_click in one tool, Button Click in another, btn_clicked in your CRM. None of them talk to each other. Your attribution is broken before you even start analyzing.

    Event naming isn’t glamorous, but it’s the difference between actionable data and a dashboard full of question marks.

    Why event names diverge

    Most operators start tracking events one tool at a time. You add GA4, fire a sign_up event. Two months later, you install a heatmap tool and track signup_button. Your email platform logs Signup with a capital S. Your payment processor calls it account_created.

    Each name made sense in isolation. But now you’re trying to connect the dots across platforms, and nothing lines up.

    The problem gets worse when multiple people touch your tracking stack. A contractor adds events with camelCase. You prefer snake_case. Your VA uses sentence case because that’s what the UI suggested. Three months later, you have 47 events and no idea which ones measure the same thing.

    Renaming events after the fact is painful. GA4 lets you modify event names via the interface, but historical data stays unchanged. Most analytics tools don’t offer retroactive renaming at all. You either live with the mess or start over.

    What a naming convention actually needs

    A useful event naming system has three jobs: it prevents duplicates, it groups related events, and it survives handoffs to other people.

    Start with a consistent case format. Snake_case (button_click) works well because it’s readable, doesn’t break in spreadsheets, and most analytics platforms handle it without fuss. Avoid spaces, capital letters, and special characters unless your tool explicitly requires them.

    Use a namespace prefix for event categories. If you track multiple funnels—say, newsletter signups and course purchases—prefix each event with its domain: newsletter_signup_started, course_checkout_completed. This keeps related events grouped in alphabetical lists and makes filtering easier.

    Be specific about the action and the object. click is too vague. button_click is better. header_cta_click is best. When you’re looking at a list of 50 events three months from now, you want to know exactly what fired without opening the implementation code.

    Write it down. A shared Google Doc, a Notion page, a comment block in your tag manager—anywhere your future self and collaborators can check before adding a new event. Include the event name, where it fires, what it measures, and when it was added. This takes two minutes per event and saves hours of detective work later.

    How to audit what you have

    Pull a full event list from each tool you use. GA4 lets you export all events from the Events report. Plausible shows them under Goals. Your CRM probably has an API endpoint or a CSV export.

    Dump everything into a spreadsheet. Look for duplicates with different casing, pluralization, or verb tenses. form_submit and form_submitted probably measure the same thing. So do page_view and pageview.

    Group events by funnel stage or user journey. Which events represent awareness? Consideration? Conversion? If an event doesn’t clearly belong to a stage, it’s either redundant or poorly named.

    Decide which names to keep. Prioritize the ones already in your most critical reports. If you’ve been running a GA4 funnel for six months with checkout_started, don’t rename it to cart_checkout_begin just for consistency. Rename the outliers instead.

    For tools that allow it, create event mappings or modify event parameters to normalize naming without losing historical data. GA4’s “modify event” feature lets you rename events going forward while keeping old data intact. Not ideal, but better than a full reset.

    For tools that don’t support renaming, add a documented transition period. Fire both the old and new event names for 30 days, then retire the old one. This gives your dashboards time to adjust without dropping data.

    When to enforce the system

    New events should follow the convention from day one. Before you add anything, check the doc. If the name isn’t there, add it. If it conflicts with an existing event, revise it before you push the code live.

    Set up a monthly review. Scan your event list for anything that doesn’t match the pattern. If you find a rogue event, trace it back to the source and fix it. The longer you wait, the harder it gets.

    If you work with contractors or team members, include event naming rules in your onboarding docs. A two-paragraph explainer and a link to your event registry will prevent most mistakes.

    This isn’t about perfectionism. It’s about making sure the data you collect six months from now is still useful. Consistent event naming doesn’t make your funnels convert better, but it makes it possible to know why they don’t.

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

  • Google Search Console property verification fails after domain transfer

    Google Search Console property verification fails after domain transfer

    Google Search Console property verification fails after domain transfer
    Photo: Iamovichowdhury via Wikimedia Commons (CC BY-SA 4.0)

    Domain transfers trigger a cascade of silent failures in Google Search Console that most operators don’t discover until weeks later, when they notice their traffic dashboard has gone dark.

    The verification token methods that worked perfectly on your old registrar—DNS TXT records, HTML file uploads, Google Analytics tags—don’t automatically follow your domain to its new home. And unlike email forwarding or DNS propagation, GSC doesn’t warn you when verification breaks. It just stops collecting data.

    Here’s what actually happens during a transfer, and how to keep your search data intact.

    Why verification breaks during domain transfers

    Google Search Console verification relies on one of five methods: DNS TXT record, HTML file upload, HTML meta tag, Google Analytics tracking code, or Google Tag Manager container. When you transfer a domain between registrars, three of these five methods break immediately.

    DNS TXT records don’t transfer automatically. Your new registrar starts with a blank DNS zone file. If you’re using Cloudflare or another DNS provider separate from your registrar, the records persist—but if your registrar was also your DNS host, that TXT record is gone the moment the transfer completes.

    HTML file verification (google1234567890abcdef.html) survives the transfer if your hosting setup doesn’t change. But many operators use registrar-bundled hosting or forwarding services that do reset during transfer. The file disappears, verification fails, and GSC stops attributing new search impressions to your property.

    Google Analytics and Tag Manager verification methods are the most resilient, because they’re embedded in your site code. They survive domain transfers intact—unless you also migrate hosting or rebuild your site during the same maintenance window.

    What you lose when verification lapses

    Google Search Console doesn’t hold your data hostage when verification fails, but it stops collecting new data immediately. Historical performance reports remain accessible for roughly 16 months, but the gap during your verification lapse creates permanent blind spots.

    You lose:

    • Real-time index coverage data. Pages submitted via sitemap during the lapse won’t show crawl status.
    • New search query performance. Impressions, clicks, and position data stop accumulating. You can’t analyze what worked—or what broke—during the gap period.
    • Core Web Vitals updates. Field data from Chrome User Experience Report keeps flowing to GSC, but you won’t see it reflected in your property until verification restores.

    Re-verification doesn’t backfill the gap. If you go dark for three weeks, those three weeks are missing from your performance graphs permanently.

    Re-verification timeline and process

    DNS TXT verification is the fastest path back. Add the TXT record to your new registrar’s DNS panel (or your separate DNS host if you use one), wait for propagation—usually 15 minutes to 4 hours—and click “Verify” in GSC. Verification completes within seconds once the record resolves.

    HTML file re-upload works if you have FTP or file manager access to your hosting root. Download the verification file from GSC, upload it to your domain root, and verify. This takes under five minutes if your hosting didn’t change.

    If you’re using Google Analytics or Tag Manager for verification and your site code didn’t change, you don’t need to do anything. GSC will continue verifying automatically. But if you removed those tags during a site redesign or platform migration that coincided with your domain transfer, you’ll need to re-implement the tracking code and re-verify manually.

    What to check before you transfer

    Log into Google Search Console 48 hours before initiating your domain transfer. Navigate to Settings → Verification details and note which method is active. If it’s DNS TXT, copy the exact record now. If it’s HTML file, download a fresh copy.

    Check whether your current registrar also hosts your DNS. If yes, export your full DNS zone file before starting the transfer. Most registrars offer a one-click export as a text file or BIND format. Import this to your new registrar or a standalone DNS host like Cloudflare immediately after the transfer completes.

    If you’re using HTML file verification and registrar-bundled hosting, switch to DNS TXT verification before the transfer. Add the TXT record as a secondary verification method, confirm it works, then transfer. This creates redundancy.

    Set a calendar reminder for 24 hours after your transfer completes. Log back into GSC and confirm your property still shows “Verified” in green. If it doesn’t, you’ll catch the lapse before days of search data disappear.

    Have a GSC verification story—or a domain transfer that went sideways? Reply to this email. We’re collecting operator war stories for a future deep-dive on DNS and domain migration pitfalls.

  • Newsletter header preloading: when Outlook blocks external images

    Newsletter header preloading: when Outlook blocks external images

    Newsletter header preloading: when Outlook blocks external images
    Photo by Markus Winkler on Unsplash

    Most newsletter platforms let you upload a header logo or hero image that sits at the top of every send. It lives on a CDN somewhere, gets referenced in your email HTML, and appears when subscribers open the message—unless they’re using Outlook with default security settings.

    Outlook blocks external images by default. That’s not new. But the way it treats image preloading—and the specific conditions under which it does load images automatically—matters more than most operators realize, especially if your branding or layout depends on that header rendering correctly.

    How Outlook’s image blocking actually works

    When someone opens an email in Outlook (desktop or web), the client checks whether the sender’s domain is in the recipient’s safe sender list. If it’s not, Outlook blocks all external image requests and shows a placeholder bar: “Right-click here to download pictures. To help protect your privacy, Outlook prevented automatic download of some pictures in this message.”

    Your logo, your hero image, your inline graphics—all blocked until the recipient manually enables images for that message or adds your sending domain to their safe list.

    This affects roughly 15–20% of B2B newsletter audiences, depending on industry. Enterprise inboxes default to Outlook, and most users never change the image settings.

    When preloading doesn’t help

    Some platforms offer “image preloading” or “image caching” as a feature. The idea: the platform fetches your images, hosts them on its own domain, and includes them inline or as cached assets so they load without external requests.

    That works for tracking pixels and some layout images, but it doesn’t bypass Outlook’s block if your header is still hosted externally—or if the platform’s CDN domain isn’t recognized by the recipient’s safe sender configuration.

    Beehiiv and MailerLite both cache images on their own delivery infrastructure, which improves load speed and reduces broken-image rates in most clients. But Outlook treats any external image request as suspect unless the sender domain (not the CDN domain) is whitelisted.

    If your header logo is a separate asset hosted on cdn.yourplatform.com, it’s still an external resource. Outlook blocks it.

    The workaround: inline data URIs

    You can embed small images directly in the email HTML using Base64-encoded data URIs. This removes the external request entirely—the image data lives in the HTML itself.

    Most platforms don’t do this automatically because it increases message size and can trigger spam filters if overused. But for a logo under 10 KB, it’s usually safe.

    In MailerLite, you can manually insert a data URI in the HTML editor. In Beehiiv, you’re limited to the visual builder unless you export and host elsewhere.

    Practical limit: keep data URIs under 15 KB per image, and use them only for critical branding elements. A 2,000-pixel-wide hero image won’t work here.

    What to test before you commit

    Send a test to an Outlook.com address and a corporate Outlook inbox if you have access. Open the message without enabling images. Check:

    • Does your header logo appear, or is it a broken placeholder?
    • Does your layout break without the hero image?
    • Is your CTA button an image, or is it HTML/CSS? (Image-based CTAs are blocked too.)

    If your layout depends on images loading, you need a text fallback or an HTML-based design that works without graphics. That’s not a compromise—it’s baseline deliverability design for any B2B audience.

    When to care about this

    If your newsletter audience skews consumer (Gmail, Apple Mail, Yahoo), Outlook image blocking is a minor edge case. Those clients load images by default.

    If you’re sending to enterprise subscribers, SaaS operators, or corporate decision-makers, Outlook is the majority client in many inboxes. Image-blocking rates jump to 30–40% in some verticals.

    Check your platform’s open-tracking data by client. If Outlook represents more than 15% of opens and your header image is external, you’re losing branding consistency for a meaningful slice of your list.

    Want to compare how different platforms handle image hosting and Outlook compatibility? Reply to this email with your current setup—we’ll add it to a future tool comparison.

    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.

  • Scheduled posts fail when APIs rate-limit by account, not by app

    Scheduled posts fail when APIs rate-limit by account, not by app

    Scheduled posts fail when APIs rate-limit by account, not by app
    Photo by Towfiqu barbhuiya on Unsplash

    Most social media scheduling tools advertise unlimited post queues. What they don’t advertise: the platform APIs they rely on impose rate limits that have nothing to do with your plan tier.

    If you’ve ever had a batch of scheduled posts fail silently, or seen a “try again later” error on content that was supposed to publish three hours ago, you’ve hit a rate limit. But the mechanism isn’t always what you think.

    Account-level vs. app-level rate limits

    Twitter’s API (now X) rate-limits by authenticated user account. If you schedule 50 posts through Publer in a day, and separately use TweetDeck or the native app to publish another 30, both actions draw from the same rate budget. The platform doesn’t care which tool sent the request—it tracks your account’s total POST calls.

    Instagram’s Graph API works differently. It rate-limits by app ID, not by user. If you’re using a scheduling tool with 10,000 other users, your posts compete with theirs for the same hourly quota. During peak hours—typically 9–11 AM Eastern on weekdays—you’re more likely to hit the wall, even if your personal queue is light.

    LinkedIn falls somewhere in between. It applies both per-user and per-app throttling, with separate limits for different content types. Publishing a text post, an image post, and a document in quick succession can trigger three different counters.

    What actually breaks

    When a scheduled post hits a rate limit, most tools retry silently. The retry window varies—Publer waits 15 minutes, Buffer waits 10, Hootsuite waits 5—but none of them guarantee the post will eventually go out. If the rate limit window extends past your scheduled time by more than the tool’s retry threshold, the post is marked failed and you get a dashboard notification. By then, it’s too late to catch the optimal posting window.

    The second failure mode is subtler: partial publishes. If you’re cross-posting the same content to Twitter, LinkedIn, and Facebook simultaneously, and Twitter’s rate limit kicks in, the other two platforms may publish successfully. Your scheduling dashboard shows “2 of 3 posted,” but unless you’re checking each platform individually, you won’t know which one failed until hours later.

    Third: cascade failures. Some tools batch API calls to save on server costs. If one post in a batch of five hits a rate limit, the entire batch can fail, even if the other four were well within quota. This is especially common with older tools that haven’t updated their API client libraries in the last 18 months.

    How to work around it

    Stagger your queue. If you’re scheduling 20 posts for the week, don’t dump them all into Monday morning slots. Spread them across off-peak hours—early morning, late evening, weekends. This reduces the chance you’ll hit app-level limits during high-traffic windows.

    Check your tool’s API authentication method. Tools that use OAuth on your behalf (you authorize them once, they act as you forever) are more likely to hit account-level limits if you’re also active on native apps. Tools that use server-to-server tokens are more likely to hit app-level limits if the service is popular.

    Use platform-specific tools for high-volume accounts. If you’re posting 10+ times a day to Twitter, use Twitter’s native scheduling instead of a multi-platform tool. Native tools have higher rate limits because they authenticate differently. The tradeoff: you lose unified analytics and cross-posting convenience.

    Monitor your tool’s status page, not just your dashboard. When Instagram’s API rate limits tighten (which happens every few months, usually with no advance notice), third-party tools post about it on their status pages or Twitter accounts. Your scheduling dashboard won’t tell you the platform changed its rules—it’ll just say “failed to publish.”

    One non-obvious fix

    If you’re hitting rate limits consistently and your posting volume isn’t extreme, check whether your scheduling tool offers a “direct publish” option instead of API-based scheduling. Some tools—Publer included—let you authorize them to post as if you were using the platform’s native interface, which bypasses third-party API quotas entirely. It’s slower, requires leaving a browser session open, and doesn’t work for all platforms, but it eliminates app-level throttling completely.

    The easier fix: schedule fewer posts. If your queue is hitting rate limits, your audience is probably hitting attention limits too.

    Got a scheduling failure you can’t explain? Reply with the tool name and platform—I’ll tell you which rate limit you hit.

    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 tool trials end mid-workflow—here’s what transfers

    Productivity tool trials end mid-workflow—here’s what transfers

    Productivity tool trials end mid-workflow—here's what transfers

    Most productivity tools offer a 14- or 30-day trial of their premium tier. You build workflows, connect integrations, upload assets, configure automations—and then the trial ends.

    What happens next depends on the tool’s architecture, not its marketing page. Some platforms gracefully downgrade you to a free plan with full data access. Others lock everything behind a paywall within seconds. A few silently delete data after 30 days.

    If you’re testing multiple tools in parallel or running a lean operation where every $20/month matters, knowing what survives a trial expiration can save you from scrambling to export or rebuild mid-project.

    What typically transfers to free plans

    Raw content and files: Documents, uploaded images, text entries, and basic records almost always stay accessible when you downgrade. Notion, Airtable, and Coda all preserve your base data—though you may lose advanced views, automations, or collaboration features.

    Manual work: Anything you created by hand—task lists, notes, spreadsheet rows—survives in most tools. Platforms make money by limiting features, not by holding your typed words hostage.

    Integration metadata, sometimes: If a tool stores data it pulled from another service (e.g., a CRM sync or calendar import), that snapshot often persists. But the live connection usually breaks immediately. You’ll see the last-synced state, frozen in time.

    What disappears when trials end

    Automation execution history: Zapier, Make, and most workflow tools delete run logs after 7–30 days, even on paid plans. On free plans, that window shrinks or vanishes. If you need to debug why an automation misfired during your trial, export logs before the clock runs out.

    Version history and rollback: Google Docs keeps edit history indefinitely on free accounts, but most productivity tools don’t. Notion’s free plan caps page history at 7 days. Airtable’s free tier offers no snapshot history at all. If you built a complex base during a trial and need to revert a breaking change post-expiration, you’re out of options.

    Shared workspaces and permissions: Collaborative features often vanish entirely. Slack’s free plan limits message history to 90 days (10,000 messages as of 2026, whichever comes first), but during a trial of a paid plan, you see everything. When the trial ends, older messages don’t get deleted—they just become invisible until you pay again. Same with Notion: guest editors you invited during a trial may lose access when you downgrade.

    Advanced exports: Free plans frequently cap export formats. You might lose the ability to download as CSV, PDF, or API-friendly JSON. ClickUp’s free plan, for example, strips bulk export and limits you to manual task-by-task copying.

    The 30-day data retention trap

    Some platforms give you a grace period after a trial ends, but it’s shorter than you think. Asana and Monday.com both warn that data may be deleted 30 days after downgrade or non-payment. In practice, most don’t purge immediately—but “may” means you have no SLA guarantee.

    If you’re juggling three trial periods and plan to pick one, set a calendar reminder for day 10 of each trial. Export everything you’d want to keep: CSV dumps, PDF reports, automation configs, integration settings. Most tools bury the export button in account settings, not the main UI.

    What to export before the timer hits zero

    For any tool you might not convert to paid, grab these before the trial ends:

    • Data exports in the most portable format: CSV or JSON over proprietary formats.
    • Integration connection details: API keys, webhook URLs, OAuth app credentials—screenshot or save them. Reconnecting later can be a headache if you don’t remember which account you linked.
    • Workflow and automation screenshots: Visual builders (Zapier, Make, n8n) don’t always let free users re-edit complex flows. A screenshot helps you rebuild elsewhere.
    • Team or workspace settings: If you invited collaborators, note who had what permissions. Some tools don’t surface this once you downgrade.

    One non-obvious tip: if a tool offers a “pause subscription” feature instead of outright cancellation, use it. Platforms like Webflow and some CRMs let you pause for 1–3 months without losing data or configuration. You stay in a paid-plan skeleton, but you’re not billed. It’s a middle ground if you’re unsure whether you’ll need the tool next quarter.

    Testing tools in parallel? Subscribe to One Two Three Send for a weekly breakdown of platform updates, trial-period traps, and migration walkthroughs—delivered every Tuesday.

    Trials are useful, but they’re designed to convert, not to give you a consequence-free sandbox. Treat day one of any trial like you’re already planning the exit. Export early, export often, and never assume “free plan” means “everything stays the same, just fewer features.” It usually doesn’t.

  • Patreon’s member-only posts don’t notify free followers—here’s why

    Patreon’s member-only posts don’t notify free followers—here’s why

    Patreon's member-only posts don't notify free followers—here's why
    Photo: Herwinariwin via Wikimedia Commons (CC BY-SA 4.0)

    Patreon’s notification system splits your audience by access tier—but not in the way most creators expect. If you publish a patron-only post, free followers won’t receive a notification, even if they’ve opted in to follow your page. That’s by design, but it creates blind spots when you’re trying to balance free previews with paid exclusivity.

    Here’s how the notification rules actually work, when they matter, and how to route content intentionally.

    How Patreon decides who gets notified

    Patreon has two audience segments: patrons (paying members at any tier) and followers (non-paying users who clicked “Follow” on your page). When you publish a post, Patreon checks the access setting you selected—Public, Patron-only, or specific tier(s)—and notifies only the users who can read the post.

    Public posts notify both patrons and followers. Patron-only posts notify only current patrons. Tier-restricted posts notify only members of the selected tiers. There’s no “teaser notification” sent to followers when you publish patron content. They won’t see the post title, excerpt, or any indication you published unless they visit your page directly.

    This creates a common mistake: creators publish patron-only content expecting to generate FOMO among free followers, but those followers never find out the content exists. The conversion lever you thought you pulled doesn’t reach them.

    When this matters for monetisation strategy

    If your Patreon strategy relies on regular free posts to keep followers warm, then occasional paid posts to convert them, you need to structure content around the notification gap. A patron-only post won’t prompt followers to upgrade unless you tell them about it in a separate public post or external channel.

    Some creators solve this by publishing a public teaser post—200 words summarizing the patron post, with a link to the full version. That public post notifies followers and gives them a reason to convert. It’s extra work, but it closes the awareness loop.

    Others use email. Patreon lets you export your follower list (not just patrons) as a CSV. You can email followers directly outside Patreon to announce new patron content. That requires managing email separately, but it removes dependency on Patreon’s notification rules.

    Tier-specific notifications and upgrade prompts

    Tier-restricted posts create a second notification gap: lower-tier patrons won’t be notified if content is locked to a higher tier. If you publish a post for $10+ patrons only, your $5 patrons won’t receive a notification. Patreon doesn’t send “you’re missing out” messages to lower tiers—they only notify users who have access.

    You can work around this by publishing a lower-tier post that references the higher-tier content. Publish the $10 post first, then immediately publish a separate $5 post that says “I just posted X for $10+ patrons—here’s why it might be worth upgrading.” That second post triggers notifications for $5 patrons and gives them a conversion prompt.

    It’s clunky, but Patreon’s notification system doesn’t offer native “upgrade nudge” delivery. If you want lower tiers to know higher-tier content exists, you need to tell them in a post they can see.

    Testing what your audience actually receives

    Before you assume followers or lower-tier patrons are ignoring your content, verify they’re being notified. Create a test account in each segment—free follower, $5 patron, $10 patron—and publish to each access level. Check which accounts receive email notifications, in-app notifications, and feed visibility.

    Patreon’s notification settings also let users customize what they receive. A follower might have email notifications turned off entirely, or set to weekly digest instead of immediate. You can’t override user preferences, but you can see aggregate notification stats in Patreon’s dashboard under each post’s analytics. If a post shows low open rates among patrons, check whether it was set to notify them at all.

    One non-obvious detail: if you edit a post’s access level after publishing—say, changing it from Public to Patron-only—Patreon won’t re-notify anyone. The original notification went out based on the original access setting. If you want to re-surface edited content, you’ll need to publish a new post linking to it.

    Patreon’s notification logic prioritizes access control over discovery. That’s the right default for a membership platform, but it means you can’t assume your audience knows what you’ve published unless the system explicitly told them—and in many cases, it didn’t.

    Want more breakdowns like this? Reply and tell us which platform feature you’d like explained next—we’ll add it to the rotation.