Author: onetwothreeadmin

  • Google Search Console click data lag: when yesterday’s spike appears next week

    Google Search Console click data lag: when yesterday’s spike appears next week

    Google Search Console click data lag: when yesterday's spike appears next week
    Photo by SumUp on Unsplash

    Google Search Console is the one traffic source most operators check daily. But the data you’re looking at isn’t live—and the lag isn’t consistent across all metrics.

    If you published something Monday and check GSC Tuesday morning hoping to see clicks, you’ll usually find nothing. The delay isn’t a bug. It’s how Google batches and processes impression and click data across billions of queries. Understanding the lag helps you avoid premature conclusions and know when a traffic change is real.

    What updates when

    Search Console breaks down into two reporting areas: Performance (clicks, impressions, CTR, position) and Index Coverage (crawl status, indexing errors).

    Performance data—the clicks and impressions you care about most—typically lags 24 to 48 hours. If you’re checking data for July 27, expect it to stabilize by July 29. The most recent day in the chart will show partial data and often updates throughout the day, but it won’t be complete until the following day.

    Index coverage updates faster. New pages submitted via sitemap or manually requested usually appear within hours. But even here, the last crawled timestamp can lag by a day.

    The Performance tab also separates Discover and Google News traffic into separate reports. These update on similar schedules, but Discover data in particular can take up to three days to fully populate—especially if your content spiked in a geography outside your primary market.

    When partial data misleads

    The most common mistake: seeing a spike in yesterday’s clicks, assuming it’s real, and writing about it—only to watch the number shrink the next day as the data finalizes.

    This happens because Google processes high-volume queries faster than long-tail ones. If your content ranks for a competitive term, early click data may show up within 24 hours. But if most of your traffic comes from hundreds of tiny queries, those clicks trickle in over 48 hours.

    The inverse is also true. A sudden drop in clicks for “yesterday” might just mean the data hasn’t loaded yet. Wait a full two days before diagnosing a traffic problem.

    One tell: if the impressions number is suspiciously low compared to the prior week’s average, the data isn’t done processing. Impressions and clicks populate together, but impressions are a higher-volume signal and tend to fill in first.

    What this means for your daily routine

    If you check GSC every morning, set your date filter to end two days ago—not yesterday. That gives you complete data and eliminates false positives.

    For real-time traffic signals, use Google Analytics 4 instead. GA4’s realtime report updates within minutes. It won’t tell you which queries drove the traffic, but it will confirm whether a spike is happening. Then return to GSC two days later to see the query breakdown.

    If you’re running a time-sensitive campaign—a product launch, a news piece, or a seasonal promo—don’t rely on GSC to measure day-one performance. Use GA4, your server logs, or a third-party rank tracker that pings hourly. GSC is for post-mortems, not live monitoring.

    When the lag stretches longer

    Occasionally, GSC data lags beyond 48 hours. This usually happens during Google algorithm updates, when the system is recalculating rankings and re-processing impression data across the index.

    If you notice a three- or four-day gap, check the Google Search Status Dashboard. Google rarely announces processing delays publicly, but operator communities on Reddit and Twitter will surface it quickly.

    Another edge case: if your site has fewer than a few hundred impressions per day, GSC sometimes batches your data less frequently. Small sites may see 72-hour lags as normal. The threshold isn’t documented, but anecdotally, sites under 500 daily impressions see slower updates.

    One workaround: the Search Console API sometimes surfaces data slightly faster than the web UI, especially for bulk queries. If you’re pulling GSC data into a dashboard or spreadsheet, the API’s freshness can beat the UI by a few hours—but you’re still looking at a 24-hour minimum lag.

    Want to catch these operator tips earlier? Subscribe to One Two Three Send—one focused article every morning, no fluff.

    The short version: treat Search Console as a lagging indicator. It’s authoritative, but it’s not fast. For daily decisions, pair it with GA4. For weekly analysis, let the data settle before you draw conclusions.

  • Beehiiv’s Boost network: how the referral swap works and who qualifies

    Beehiiv’s Boost network: how the referral swap works and who qualifies

    Beehiiv's Boost network: how the referral swap works and who qualifies
    Photo by Haithem Ferdi on Unsplash

    Beehiiv‘s Boost network lets you trade recommendations with other newsletters—your publication shows up in someone else’s inbox, theirs shows up in yours. The pitch is simple: pay-per-subscriber acquisition without managing individual cross-promo deals.

    But Boost isn’t a passive referral lottery. The network uses an internal matching algorithm, a credit system, and quality gates that determine whether your newsletter gets shown at all. If you’re considering it—or already enrolled and wondering why results are inconsistent—here’s how the mechanics actually work.

    How the credit system allocates impressions

    Boost runs on credits, not cash. You earn credits when another newsletter recommends yours to their readers. You spend credits when Beehiiv shows your newsletter to someone else’s audience.

    Each recommendation costs one credit. If someone subscribes after seeing your Boost placement, you’re charged that credit. If they don’t subscribe, you still pay—the credit covers the impression, not the conversion.

    You can buy credits directly (around $1–$2 per credit depending on volume), or earn them by letting other newsletters appear in your recommendations. The latter is how most operators start: you allocate a percentage of your subscriber recommendations to Boost partners, and Beehiiv credits your account based on impressions served.

    The non-obvious part: credit earn rates aren’t uniform. Beehiiv weighs your newsletter’s engagement, open rates, and subscriber quality. A newsletter with 5,000 engaged readers earns more credits per impression than one with 20,000 cold subscribers. The platform doesn’t publish the exact formula, but operators report earn-rate variance between 0.6× and 1.4× depending on performance.

    Who sees your newsletter—and who doesn’t

    Boost placements aren’t random. Beehiiv’s algorithm tries to match newsletters by topic, audience overlap, and engagement profile. If you run a B2B SaaS newsletter, you’re more likely to appear in recommendations for other business-focused publications than in a gardening newsletter’s rotation.

    But topic match is only one filter. Beehiiv also applies a quality floor. Newsletters with open rates below ~30%, high spam-complaint rates, or recent deliverability issues get deprioritized or removed from Boost rotation entirely. The platform doesn’t send warnings—you’ll just stop seeing credit accrual or impression delivery.

    There’s also an implicit size gate. Boost works best for newsletters between 1,000 and 50,000 subscribers. Below 1,000, your earn rate is too low to generate meaningful credit flow. Above 50,000, the network’s inventory can’t deliver enough relevant impressions to match your spending pace, and you’ll end up buying credits instead of earning them.

    When Boost makes sense—and when it doesn’t

    Boost is worth testing if:

    • You’re between 2,000–25,000 subscribers and growth has plateaued
    • Your open rate is consistently above 35%
    • You’re comfortable letting 10–20% of your recommendation slots go to Beehiiv’s algorithm
    • Your niche has enough adjacent newsletters in the network (B2B, tech, finance, and creator economy are well-represented; hyper-local or non-English niches are sparse)

    It’s not worth it if:

    • You’re under 1,000 subscribers—earn rates are too low, and you’ll pay cash for every placement
    • Your content is highly specific or regional; the algorithm struggles to find relevant matches
    • You’ve already built strong 1:1 cross-promo relationships—direct swaps give you more control and often better conversion rates

    Typical cost-per-subscriber via Boost ranges from $1.50 to $4.00 depending on niche and how well your newsletter converts cold traffic. That’s competitive with paid ads but less predictable. Some operators report CPS under $1; others burn through $500 in credits and acquire 80 subscribers, most of whom churn within two sends.

    One non-obvious tip: front-load your best content

    Boost subscribers arrive cold. They clicked a recommendation, but they don’t know you yet. If your welcome sequence is generic or your next few sends are off-brand, they’ll unsubscribe fast—and Beehiiv’s algorithm will notice.

    Operators who see sustained Boost performance treat the first three emails as an onboarding sprint: high-value, hyper-relevant, and faster-paced than their usual cadence. If your regular newsletter goes out weekly, consider sending Boost-sourced subscribers a second touchpoint within 48 hours. Retention after three emails is the strongest signal Beehiiv uses to keep recommending your newsletter.

    If you’re already on Beehiiv and considering Boost, run a small test: allocate 10% of recommendations for 30 days, track cost-per-subscriber and 30-day retention separately, and compare it to your other acquisition channels. If CPS and retention both land in your top three sources, scale up. If not, redirect the effort to direct cross-promo outreach or paid social.

    Using Beehiiv and want to compare notes on what’s working? Reply to this email—I’ll feature anonymized operator data in a future case study.

    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.

  • Stripe tax calculation sync delays: when checkout totals don’t match

    Stripe tax calculation sync delays: when checkout totals don’t match

    Stripe tax calculation sync delays: when checkout totals don't match
    Photo by FIN on Unsplash

    If you’re running subscriptions or one-off product sales through Stripe and you’ve turned on automated tax calculation, you’ve probably assumed the displayed total at checkout matches what Stripe will actually charge. Most of the time it does. But there’s a timing issue that breaks this assumption, and it shows up more often than Stripe’s documentation admits.

    The problem: Stripe’s Tax Calculation API is called asynchronously when a customer reaches checkout. If your checkout page renders faster than the tax calculation response returns—common on fast hosting or CDN-cached pages—the displayed price can lag behind by a second or two. When that happens, the customer sees one total, then it flickers to another, or worse, the charge goes through before the tax rate applies.

    How Stripe’s tax calculation actually fires

    Stripe’s tax engine doesn’t pre-calculate tax for every possible customer location. Instead, it waits until checkout to call POST /v1/tax/calculations with the customer’s IP-derived location, the line items, and your tax settings. The response includes the tax amount, which your frontend then adds to the subtotal.

    This works fine when checkout is slow—legacy WordPress installs, heavy JavaScript bundles, or multi-step forms give the API enough time to respond before the total renders. But if your checkout loads in under 800ms and you’re calling the API client-side, you’ll see the mismatch.

    Stripe recommends server-side calculation for this reason, but many solo operators use client-side Stripe.js integrations or no-code tools like MemberStack, Outseta, or Carrd payment embeds, which default to client-side tax calls.

    When the lag causes real problems

    The flicker alone erodes trust. A customer sees $49, then $53.67 a moment later. If they screenshot the first number or bail before the update, you’ve lost the sale or opened a dispute.

    Worse: if your payment button becomes active before the tax calculation completes, Stripe will process the charge without tax. You’re liable for the shortfall. This happens most often when operators use custom checkout forms that don’t wait for Stripe’s PaymentIntent status to confirm tax has been applied.

    Third issue: webhook events. If you’re listening for checkout.session.completed to trigger fulfillment, and the tax calculation hasn’t finished, your webhook payload might show an incomplete amount_total. Fulfillment scripts that check totals against expected pricing will fail or flag fraud.

    How to fix it

    Move tax calculation server-side if you control your checkout stack. Create the PaymentIntent on your backend, call /v1/tax/calculations there, and return the final total to the frontend. This ensures tax is baked in before the customer sees any number.

    If you’re locked into a client-side tool, add a loading state to your checkout button. Disable it until Stripe confirms automatic_tax.status returns complete. Most no-code platforms let you add a custom attribute or visibility rule tied to a calculation flag.

    For webhook reliability, always validate amount_total in your handler. If it’s lower than expected and automatic_tax.status is requires_location or failed, log it and retry the calculation manually via the API before fulfilling.

    One non-obvious fix: cache customer location in a session cookie after their first page load, then pre-calculate tax before they hit checkout. This won’t work for first-time visitors, but it smooths repeat traffic. You can use Stripe’s customer_details.address field to store validated location data from a prior purchase.

    Pricing and support notes

    Stripe Tax costs 0.5% of the transaction amount plus any tax collected, with a $10/month minimum once you process your first taxable sale. The API itself has no rate limit for tax calculations, but each call adds ~200–400ms latency depending on region.

    If you’re processing under 100 transactions a month, the $10 minimum might not justify automation—manual tax rates via Stripe’s dashboard are free and load instantly. For higher volume or multi-region sales, automated tax is worth it, but only if you handle the sync timing correctly.

    Stripe’s support documentation assumes you’re using Checkout or Payment Links, both of which handle tax calculation timing internally. If you’ve built a custom integration, you’re on your own to catch these edge cases.

    Have a checkout or payment flow question? Reply to this email—operator questions shape what we cover next.

  • AI prompt templates fail when context drifts—version them

    AI prompt templates fail when context drifts—version them

    AI prompt templates fail when context drifts—version them
    Photo by Daria Nepriakhina 🇺🇦 on Unsplash

    If you’ve built a library of AI prompts that worked beautifully in March and now produce garbage in July, you’re not alone. The problem isn’t the model—it’s context drift, and most solo operators don’t version their prompts the way they version code.

    AI models change. Your business changes. The examples you fed into a prompt six months ago referenced products you no longer sell, a tone you’ve since abandoned, or input data structured in a format you’ve updated twice. When you paste that prompt into Claude or ChatGPT today, it misfires—and you waste twenty minutes editing output instead of moving on.

    Here’s how to version AI prompts so they stay useful, and when to retire them entirely.

    Why prompts degrade faster than you think

    Three things break prompts over time:

    • Model updates. OpenAI and Anthropic ship new versions every few months. A prompt optimized for GPT-4 in early 2026 may produce different results on the July release, even if the underlying capability improved. Temperature defaults, token handling, and instruction-following behavior all shift.
    • Your own vocabulary drift. You wrote a prompt template in February using placeholder variables like {{product_name}} and {{target_audience}}. By June, you’ve segmented your audience into three tiers, renamed your flagship product, and introduced a new content format. The old prompt doesn’t know any of this.
    • Corpus updates. If your prompt references specific URLs, doc IDs, or brand names, and any of those change, the AI hallucinates or defaults to generic output. A prompt that said “tone should match our About page at example.com/about” fails silently when you redesign the site and move that content.

    The result: you keep a folder of prompts, reuse one that used to work, and spend more time fixing the output than if you’d written from scratch.

    How to version prompts like code

    Treat each prompt as a versioned artifact. When you create or update a prompt that you’ll reuse, save it with a version number and a changelog note. This doesn’t require Git—a plain text file or a Notion doc works fine.

    Example structure:

    social-caption-v3.txt
    Last updated: 2026-07-15
    Changes: Removed reference to discontinued course; added instruction to include CTA link; clarified character limit to 280.

    When the prompt stops working well, duplicate it, update it, and increment the version. Keep the old one in an archive folder. If the new version performs worse, you can roll back and compare what changed.

    This costs you thirty seconds per update. It saves you fifteen minutes every time you revisit the prompt and wonder why it’s producing weaker output than you remember.

    Test prompts on sample data before you commit

    Before you version and archive a prompt, run it against three sample inputs that represent real use cases. Save the outputs. This creates a regression test.

    When you update the prompt, run the same three samples again. If the new version produces noticeably worse results on any of them, you’ve caught a regression before it cost you production time.

    This is especially useful for prompts that generate structured output—JSON, CSV, or formatted tables. A small wording change can break parsing logic downstream.

    When to retire a prompt entirely

    Not every prompt should be versioned forever. If you haven’t used a prompt in sixty days, it’s probably no longer relevant. Archive it separately or delete it.

    If you’ve versioned the same prompt four or five times and each version required substantial rewrites—not just tweaks—the underlying task has probably evolved beyond what a single template can handle. At that point, you’re better off writing fresh prompts on demand or splitting the task into smaller, more stable sub-prompts.

    Versioning is useful when the task is stable but the context shifts. If the task itself is unstable, the prompt library becomes clutter.

    One small addition that prevents most drift

    Add a dateline to every prompt: Context as of: July 2026.

    This reminds you—and the AI—that the instructions were written for a specific moment. When you revisit the prompt six months later, that dateline signals that you should review it before running it. It’s a forcing function that costs zero tokens and prevents silent degradation.

    Prompt versioning isn’t glamorous. But if you’re running a content business and relying on AI for drafts, summaries, or structured data extraction, unversioned prompts are technical debt. You’ll pay it back in wasted output and rework time.

    Got a prompt versioning system that works for you? Reply and tell us—we’ll feature operator workflows in a future piece. And if you want more AI tool breakdowns like this, subscribe to One Two Three Send for weekly deep dives on the tools solo operators actually use.

    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 post revisions database bloat: when to cap and purge

    WordPress post revisions database bloat: when to cap and purge

    WordPress post revisions database bloat: when to cap and purge
    Photo: Simone Bignetti via Wikimedia Commons (CC BY-SA 4.0)

    WordPress saves every draft change you make as a post revision. Every autosave, every manual save, every time you click update. Those revisions live forever in the wp_posts table unless you explicitly limit or purge them.

    For a solo operator publishing twice a week, this rarely matters. For a site with daily posts, guest contributors, or heavy editing cycles, you can end up with tens of thousands of revision rows that slow down queries, inflate backups, and make database migrations painfully slow.

    Here’s when revisions become a problem, how to cap them, and what happens when you purge old ones.

    How revisions accumulate faster than you think

    WordPress creates a new revision on every save—manual or automatic. The default autosave interval is 60 seconds. If you spend 20 minutes editing a post and save manually three times, you’ve just created roughly 23 revisions for a single post.

    Multiply that across a year of publishing, especially if you have multiple authors or use tools that auto-update posts (like content refreshers or dynamic blocks), and you’re looking at 5,000–15,000 revision rows per year for a modest site.

    Each revision is a full duplicate of the post content at that moment—title, body, meta. It’s not a diff. That’s why a site with 500 published posts can have 8,000 rows in wp_posts.

    When revisions start causing real problems

    Revisions don’t directly slow down your front end—visitors never query them. But they do three things that hurt:

    • Admin dashboard queries slow down. The post editor loads all revisions for the current post. If a single post has 200 revisions, that’s a noticeable lag when you open it.
    • Backup file sizes balloon. Your nightly database backup includes every revision. A 50 MB database becomes 200 MB, which slows down both the backup process and restores.
    • Database exports and migrations take longer. If you’re moving hosts or cloning a site, you’re waiting for thousands of unnecessary rows to export and import.

    You’ll notice the impact most clearly when running a plugin like WP-Optimize or querying the database directly. A SELECT that should return 500 posts instead scans 8,000 rows because revisions share the same table.

    How to cap revisions going forward

    Add this line to your wp-config.php file, anywhere above the line that says /* That's all, stop editing! */:

    define( 'WP_POST_REVISIONS', 5 );

    This limits WordPress to keeping the five most recent revisions per post. Older revisions are automatically deleted when a new one is created.

    Five is a sensible default for most solo operators. It’s enough to undo a bad edit or recover from an accidental overwrite, but not so many that you’re hoarding years of draft history you’ll never look at.

    If you want to disable revisions entirely, set it to false:

    define( 'WP_POST_REVISIONS', false );

    This stops all future revisions. Autosave still works—you can still recover unsaved changes—but WordPress won’t store a permanent history.

    How to purge existing revisions

    Capping revisions only affects new saves. It doesn’t touch the thousands of old revisions already sitting in your database.

    To remove those, you have two options: a plugin or a direct SQL query.

    Plugin method: Install WP-Optimize (free) or WP Sweep (free). Both have a one-click option to delete all post revisions. WP-Optimize also lets you schedule automatic cleanups weekly or monthly.

    SQL method: If you’re comfortable with database access, run this query in phpMyAdmin or your host’s database tool:

    DELETE FROM wp_posts WHERE post_type = 'revision';

    This deletes every revision from your database immediately. Make sure you have a backup first—this is irreversible.

    After running the query, also run OPTIMIZE TABLE wp_posts; to reclaim the disk space and rebuild the table index. Without this step, your database file size won’t actually shrink.

    The tradeoff: losing granular undo history

    Capping or purging revisions means you can’t travel back to a draft from six months ago. For most operators, that’s fine—you’re not auditing edit history or rolling back to ancient versions.

    But if you’re running a site with compliance requirements, guest contributors who might dispute changes, or content that frequently gets reverted (like policy pages or legal disclaimers), keep more revisions or use a version-control plugin like Revisionary or WP Document Revisions instead.

    For everyone else, five revisions and an annual purge is a reasonable maintenance habit that keeps your database lean without sacrificing practical undo capabilities.

    If you’re dealing with WordPress performance issues beyond revisions—caching, plugin conflicts, or database optimisation—reply and let me know what’s slowing you down. I’ll cover it in a future piece.

  • Social media automation token expiry: when connections break silently

    Social media automation token expiry: when connections break silently

    Social media automation token expiry: when connections break silently
    Photo by Deng Xiang on Unsplash

    Most social media automation tools connect to platforms using OAuth tokens. These tokens grant permission for one app to post, read analytics, or manage content on your behalf. They’re invisible until they stop working.

    The problem: tokens expire. Some platforms revoke them after 60 days of inactivity. Others refresh them automatically—until they don’t. When a token dies, your scheduled posts vanish into the void, your cross-posting stops, and you won’t know until you check manually or a follower asks why you went quiet.

    Here’s what actually happens, platform by platform, and how to catch failures before they cost you a week of missing content.

    How long tokens last, and what triggers expiry

    Twitter/X: Access tokens don’t expire on a fixed schedule, but the platform can revoke them if you change your password, revoke app permissions, or if Twitter detects suspicious API activity. In practice, tokens last months—until they don’t. No warning email.

    LinkedIn: Access tokens expire after 60 days. Refresh tokens last 12 months. If your automation tool doesn’t request a new access token within that 60-day window, the connection dies. LinkedIn sends no notification when this happens. Your posts just stop going out.

    Facebook/Instagram (Meta): Short-lived tokens expire in one hour. Long-lived tokens last 60 days. Most tools exchange short for long automatically, but if you don’t generate user activity within 60 days, the token goes stale. Meta’s Business Suite sometimes emails you, but the Developer dashboard doesn’t surface token health unless you check manually.

    YouTube: Refresh tokens don’t expire unless revoked manually or the account is inactive for six months. Google sends no proactive alert.

    The common thread: expiry is silent. Platforms assume the app developer—not you, the end user—will handle monitoring.

    What breaks when a token dies

    Most automation tools fail gracefully in the UI—they’ll show “connection lost” or “re-authenticate”—but they don’t always notify you by email or Slack. If you’re not logging into the tool daily, you won’t see it.

    Here’s what stops working:

    • Scheduled posts queue locally but never publish
    • Cross-posting from RSS feeds or your CMS halts
    • Analytics dashboards stop updating
    • Auto-replies, comment moderation, or DM automation freeze

    Some tools retry silently for 24–48 hours, then mark the post as failed. Others drop it entirely. Publer surfaces connection errors in its dashboard and sends email alerts if a publish attempt fails, but only if you’ve enabled notifications in settings—it’s off by default.

    Buffer queues failed posts and flags them, but won’t re-attempt after the connection is restored unless you manually reschedule. Hootsuite logs errors in the activity feed, but doesn’t push a notification unless you’ve configured a webhook.

    How to catch token expiry before it breaks your workflow

    Enable failure notifications in your scheduler. Every tool has this setting buried somewhere. Turn on email or Slack alerts for failed publishes, not just successful ones.

    Set a monthly calendar reminder to check connected accounts. Log in, review the integrations page, and confirm each platform shows “connected” with a recent timestamp. If a token is about to expire, some tools show a yellow warning icon—but only if you’re looking.

    Test with a throwaway post once a month. Schedule a post to all connected accounts for immediate publish, then verify it went live. Delete it 60 seconds later. This forces the tool to use the live token and surfaces any silent failures.

    Use a secondary monitoring tool if your workflow is critical. If you’re running a client account or a high-frequency publishing schedule, set up a simple uptime monitor that checks your social profiles for new posts. services like UptimeRobot or a custom Zapier workflow can ping you if no new content appears within an expected window.

    When to re-authenticate vs. when to rebuild the connection

    If your tool shows “re-authenticate,” clicking the button usually refreshes the token without losing your queue or settings. Do this immediately.

    If the re-auth flow fails—common with LinkedIn and Meta—you’ll need to fully disconnect and reconnect the account. This often clears your scheduled post queue for that platform. Before disconnecting, screenshot or export your queue. Most tools don’t preserve drafts when you sever a connection.

    Some operators keep a backup auth token in a separate tool (e.g., one account connected in Buffer, the same account also connected in Publer) so if one breaks, the other can cover while you troubleshoot. This adds overhead, but it’s cheaper than losing a week of posts.

    Want to avoid these silent breaks? Subscribe to One Two Three Send for operator-focused breakdowns of what actually fails—and how to fix it before it costs you traffic.

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

  • ConvertKit broadcast send-time personalisation: how it decides

    ConvertKit broadcast send-time personalisation: how it decides

    ConvertKit broadcast send-time personalisation: how it decides
    Photo by Kit (formerly ConvertKit) on Unsplash

    ConvertKit’s broadcast scheduler includes a checkbox labelled “Optimise send time.” When enabled, the platform doesn’t deliver your email at the moment you hit publish—it queues each subscriber’s copy for a window it thinks they’re most likely to engage.

    The feature sounds useful. In practice, it works well for some operators and creates confusion for others. Here’s what actually happens under the hood, when the algorithm helps, and when you’re better off choosing a fixed send time.

    What the algorithm looks at

    ConvertKit’s send-time optimisation scans each subscriber’s engagement history: opens, clicks, and the timestamps associated with both. It looks for patterns—does this person consistently open emails around 7 a.m. Eastern? Do they engage more on weekday mornings or weekend afternoons?

    If the platform identifies a statistically significant pattern, it schedules delivery within a window it predicts will perform better than a one-size-fits-all broadcast time. If no pattern exists—new subscribers, inactive readers, or those with erratic habits—it defaults to your account’s standard send time or the time you manually set when creating the broadcast.

    The optimisation window spans roughly 24 hours. ConvertKit won’t hold a broadcast for days, but it will stagger delivery across morning, afternoon, and evening slots depending on subscriber behaviour.

    When it helps

    Send-time optimisation works best when you have a large, engaged list with diverse time zones and consumption habits. If you’re sending to 10,000 subscribers spread across North America, Europe, and Asia, the feature can lift open rates by 2–8% compared to a single fixed time.

    It’s also useful when your content isn’t time-sensitive. Evergreen tutorials, weekly roundups, and educational sequences don’t lose value if they arrive six hours later than your publish click. The algorithm prioritises engagement over synchronicity.

    Operators who publish frequently—three or more broadcasts per week—also see better results. The platform accumulates more engagement data, which sharpens its predictions. If you send once a month, there’s less signal to work with.

    When manual scheduling wins

    Time-sensitive broadcasts break the optimisation logic. If you’re announcing a product launch, a limited-time discount, or commentary tied to a news event, you want simultaneous delivery. Staggering emails across 24 hours means some subscribers see the offer after it’s expired or the news cycle has moved on.

    Small lists—under 1,000 subscribers—don’t benefit much either. The algorithm needs volume to identify statistically meaningful patterns. With a few hundred people, manual scheduling based on your own audience knowledge often outperforms the automated approach.

    And if your list skews heavily toward a single time zone or demographic, the optimisation adds complexity without much upside. A newsletter serving U.S. East Coast professionals during weekday work hours doesn’t need personalised delivery windows—everyone’s already in the same behaviour bucket.

    One non-obvious tip

    ConvertKit’s send-time optimisation relies on opens as its primary engagement signal, but open tracking has degraded since Apple’s Mail Privacy Protection rolled out in 2021. A meaningful percentage of your subscribers now register artificial opens the moment an email hits their inbox, regardless of when they actually read it.

    This skews the algorithm’s predictions. If you notice erratic or counterintuitive delivery patterns—emails going out at odd hours, open rates drifting downward despite optimisation being enabled—try disabling the feature for two or three broadcasts and compare performance. Manual scheduling at a consistent, tested time often performs better when open-tracking reliability is compromised.

    You can also cross-reference your ConvertKit open data with click data, which remains accurate. If the platform says a subscriber opens at 6 a.m. but consistently clicks at noon, the optimisation may be misfiring. In that case, fall back to manual control.

    Want more breakdowns like this? Subscribe to One Two Three Send for weekly deep-dives on the tools and tactics that actually move the needle for solo operators.

  • SEO title tags longer than 60 characters: what Google actually shows

    SEO title tags longer than 60 characters: what Google actually shows

    SEO title tags longer than 60 characters: what Google actually shows
    Photo by Growtika on Unsplash

    Google’s title tag rewriting has gotten aggressive. Even when you write a clean, keyword-focused title, there’s no guarantee that’s what shows up in search results—especially if your title runs long.

    The old rule was simple: keep titles under 60 characters and you’re safe. That’s no longer true. Google now rewrites titles based on query context, page content, and its own interpretation of relevance. But character count still matters, and understanding where the cutoff happens—and what Google does when it hits that limit—can save you from losing clicks to ellipses or mangled rewrites.

    The 60-character guideline is a pixel width estimate, not a hard limit

    Google doesn’t count characters. It measures pixel width. A title with narrow letters like “i” and “l” can stretch past 70 characters and still display fully. A title packed with wide characters like “W” and “M” might get cut at 55.

    The commonly cited 60-character limit assumes an average character width of about 10 pixels, with a total display width around 600 pixels on desktop. Mobile widths are narrower—closer to 78 characters at roughly 920 pixels, but that varies by device and font rendering.

    Practically: if your title is under 60 characters, it’ll almost always display in full. Between 60 and 70, you’re gambling. Past 70, expect truncation or a rewrite.

    When Google truncates vs. when it rewrites entirely

    Truncation is the clean outcome. Your title gets cut mid-sentence and an ellipsis (…) appears. You lose the tail, but the front still represents what you wrote.

    Rewriting is messier. Google pulls text from your H1, meta description, or prominent on-page copy and generates a new title that may not match your intended keyword targeting at all. This happens more often when:

    • Your title is vague or keyword-stuffed
    • Your title doesn’t match the user’s query well
    • Your page has a strong H1 that differs significantly from the title tag
    • Your title exceeds roughly 70 characters and Google decides truncation would be unhelpful

    There’s no deterministic trigger. In testing across a few dozen client sites in early 2026, titles longer than 65 characters were rewritten about 40% of the time, while titles under 55 characters were rewritten less than 10% of the time—but only when the title and H1 were closely aligned.

    How to test what actually appears before you hit publish

    Don’t rely on SERP preview tools in your SEO plugin. They estimate based on character count, not actual Google rendering.

    The most reliable method: publish the page, wait 24–48 hours for indexing, then search for site:yourdomain.com "exact phrase from title" and see what Google shows. If it’s truncated or rewritten, you know before any traffic arrives.

    For faster iteration, use Google’s Rich Results Test or the URL Inspection tool in Search Console. Neither shows the exact SERP title, but they confirm whether your title tag is being read correctly and flag any HTML issues that might trigger a rewrite.

    If you’re split-testing title length, track CTR by title length cohort in Search Console. Filter by page, compare average position to CTR, and look for drop-offs where longer titles perform worse despite similar rankings. That’s your signal to trim.

    The non-obvious move: write for truncation, not against it

    Most operators try to stay under 60 characters to avoid truncation entirely. That’s safe, but it leaves opportunity on the table.

    If you front-load your title with the core keyword and value proposition in the first 50 characters, you can extend the tail with secondary keywords or modifiers that add context for Google’s algorithm—even if users never see them in the SERP.

    Example:
    Short, safe version (52 characters):
    “WordPress CDN setup: Cloudflare configuration guide”

    Extended version (68 characters):
    “WordPress CDN setup: Cloudflare configuration guide for speed & caching”

    The second version might get truncated to “WordPress CDN setup: Cloudflare configuration guide for spe…” in search results, but Google still indexes “speed” and “caching” as relevance signals. You get the ranking boost without sacrificing clarity in the visible title.

    This works best for informational content where secondary keywords reinforce the main topic. It’s riskier for commercial pages where every word in the SERP title needs to convert.

    Want more tactical breakdowns like this? Hit reply and tell us which part of your stack is giving you the most trouble right now—we’ll cover it in an upcoming issue.

  • Sponsored newsletter placements: actual CPM ranges by niche in 2026

    Sponsored newsletter placements: actual CPM ranges by niche in 2026

    Sponsored newsletter placements: actual CPM ranges by niche in 2026
    Photo by mauRÍCIO SANTOS on Unsplash

    If you’re thinking about selling sponsorships in your newsletter, the first question is always: what should I charge?

    Most advice points to CPM—cost per thousand opens—but the ranges you’ll find online are either outdated or so wide they’re useless. Here’s what solo operators and small teams are actually charging in 2026, broken down by niche, list size, and placement type.

    Tech and developer newsletters: $30–$80 CPM

    Tech newsletters with engaged audiences—especially those covering specific tools, frameworks, or workflow topics—command some of the highest rates. A 5,000-subscriber list with a 40% open rate (2,000 opens) can charge $60–$160 for a primary placement.

    The upper end applies when your audience skews toward decision-makers: CTOs, senior engineers, product leads. If your readers are junior devs or students, expect $30–$50 CPM.

    Sponsors in this niche are typically SaaS tools, API platforms, or developer-focused services. They’re buying access to builders who have budget authority or influence over stack decisions.

    Finance, investing, and business: $40–$100 CPM

    Newsletters covering personal finance, investing strategies, or small-business operations sit in a similar range—or higher if the audience is verified high-net-worth.

    A business newsletter with 10,000 opens can charge $400–$1,000 per placement. Sponsors here include fintech apps, investment platforms, business insurance, and accounting tools.

    The key variable is audience income and intent. If your readers are actively managing portfolios or running businesses, CPMs climb. If they’re browsing general money tips, rates drop toward $25–$40.

    Marketing and creator tools: $25–$60 CPM

    Newsletters for marketers, solo operators, and content creators—like this one—typically see $25–$60 CPM. Sponsors are often other newsletters, SaaS tools, courses, or affiliate offers.

    A list with 8,000 opens might charge $200–$480 for a dedicated sponsor block. Secondary placements (classified-style listings or brief mentions) go for $15–$30 CPM.

    This niche is crowded, and many readers are also operators who know what sponsorships cost. That keeps rates honest but also means you need strong engagement metrics—open rates above 35% and click-through above 2%—to justify premium pricing.

    Lifestyle, wellness, and general interest: $15–$40 CPM

    Broader lifestyle newsletters—covering travel, productivity, wellness, or general personal development—sit at the lower end. CPMs range from $15 to $40 depending on engagement and audience demographics.

    A 15,000-open newsletter in this category might charge $225–$600 per sponsor. The challenge is that sponsors often want very specific audience segments (parents, remote workers, specific age ranges), and general-interest lists don’t always deliver that precision.

    Higher rates come from tight positioning. A newsletter for remote-working parents will out-earn a general productivity newsletter with the same open count.

    What actually moves the rate

    Niche matters, but three other factors determine what you can charge:

    • Engagement rate: Opens above 40% and clicks above 3% let you charge 20–30% more than average.
    • Audience intent: Readers who buy tools, subscribe to services, or make business decisions are worth more than passive readers.
    • Sponsor fit: A tight match between your content and the sponsor’s product doubles conversion and justifies premium pricing.

    If you’re just starting, aim for the lower end of your niche’s range. Once you have case studies showing sponsor ROI—real click-through and conversion data—you can move toward the top quartile.

    Where to list your availability

    Most solo operators start by mentioning availability in their newsletter footer or a dedicated sponsor page on their site. Tools like Swapstack, Paved, and SparkLoop’s ad network can connect you with sponsors, though they typically take 20–30% of the placement fee.

    Direct outreach to brands you already use or cover often yields better rates and longer-term relationships. Send a one-page media kit with your open rate, audience breakdown, and two pricing tiers: primary placement and secondary mention.

    If your newsletter runs on Beehiiv, their built-in ad network can match you with sponsors automatically once you hit 500+ subscribers, though CPMs through the network tend to sit at the lower end of these ranges.

    Want more data on what’s working in newsletter monetisation? Reply with your niche and list size—I’ll share what operators in similar categories are seeing.

    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 multisite subdomain DNS: how wildcard A records actually work

    WordPress multisite subdomain DNS: how wildcard A records actually work

    WordPress multisite subdomain DNS: how wildcard A records actually work
    Photo by Markus Spiske on Unsplash

    WordPress multisite with subdomains sounds elegant in theory: every new site gets sitename.yourdomain.com instead of yourdomain.com/sitename. But the DNS configuration required to make that work trips up even experienced operators, especially when a CDN sits in front.

    If you’ve ever added a new multisite subsite and found it unreachable for hours—or had some subsites resolve while others don’t—the issue is almost always in how your wildcard A record is configured, cached, or overridden.

    What wildcard DNS actually does

    A wildcard A record in your DNS zone looks like this:

    *.yourdomain.com. A 192.0.2.10

    That asterisk tells the nameserver: “for any subdomain that doesn’t have an explicit record, send traffic to this IP.” So when someone visits newsite.yourdomain.com, and you haven’t manually created a DNS entry for newsite, the wildcard catches it and routes it to your server.

    WordPress multisite then inspects the HTTP Host header, matches it to a subsite in the database, and serves the right content. The wildcard doesn’t create the site—it just ensures the request reaches your server.

    But here’s the catch: wildcard records have lower priority than explicit records. If you’ve previously created an A record for staging.yourdomain.com pointing elsewhere, the wildcard won’t override it. That explicit record wins.

    When propagation stalls and caching hides the issue

    DNS records have a Time-To-Live (TTL) value, usually between 300 seconds (5 minutes) and 86400 seconds (24 hours). When you add or change a wildcard A record, recursive resolvers—like those run by ISPs or Cloudflare’s 1.1.1.1—cache the old state until the TTL expires.

    If your previous wildcard record had a 24-hour TTL and you just changed the IP, some visitors won’t see the update for a full day. Your local machine might resolve correctly (because your DNS client happened to refresh), but your phone on cellular data still hits the old IP.

    This creates a debugging mirage: the site works for you, fails for others, and you can’t reproduce the issue. The fix is to lower your wildcard A record TTL to 300 seconds before making changes, wait for the old TTL to expire, then make the change. After it propagates, you can raise the TTL again if you want.

    The CDN wildcard gotcha

    If you’re using a CDN like Cloudflare, BunnyCDN, or Fastly, the wildcard DNS record alone isn’t enough. Most CDNs require you to explicitly enable wildcard proxying or add each subdomain to a whitelist.

    On Cloudflare, for example, wildcard DNS records (*.yourdomain.com) can be proxied (orange cloud), but only on Business or Enterprise plans. On Free and Pro plans, the wildcard record must be DNS-only (grey cloud). That means requests hit your origin server directly—no CDN caching, no DDoS protection, no automatic SSL for new subsites.

    If you’re on a CDN plan that doesn’t support wildcard proxying, you have two options:

    • Upgrade the CDN plan to enable wildcard SSL and proxying.
    • Pre-create DNS records for each subsite manually and proxy those individually. This works, but it defeats the automation benefit of multisite subdomains.

    BunnyCDN supports wildcard pull zones on all plans, but you need to configure the hostname pattern in the pull zone settings. If you skip that step, the CDN won’t know which origin to pull from, and requests fail with a 404 at the edge.

    Non-obvious tip: test with dig, not a browser

    When you’re debugging wildcard DNS, don’t rely on your browser. Browsers cache DNS internally, and your OS has its own resolver cache. Instead, use dig or nslookup to query the authoritative nameserver directly:

    dig @ns1.yourprovider.com randomsubdomain.yourdomain.com

    Replace ns1.yourprovider.com with one of your domain’s authoritative nameservers (find them with dig yourdomain.com NS). If the wildcard is configured correctly, you’ll see an A record response with your origin IP, even for a subdomain that doesn’t exist in WordPress yet.

    If dig returns NXDOMAIN, the wildcard isn’t live yet—either it hasn’t propagated, or it wasn’t saved correctly in your DNS provider’s dashboard.

    When to use multisite subdomains vs. subdirectories

    Subdomain multisite makes sense when you’re running distinct properties under one WordPress install—think a network of regional sites, or client sites you manage centrally. But if you’re a solo operator running one content brand, subdirectories (yourdomain.com/blog, yourdomain.com/shop) are simpler. You avoid DNS complexity, CDN wildcard restrictions, and SSL certificate headaches.

    Subdomain multisite also complicates migration. Moving to a new host means updating the wildcard A record and waiting for propagation. With subdirectories, you update one A record and you’re done.

    If you’re already committed to subdomain multisite and hitting DNS or CDN issues, the fix is usually one of three things: lower TTL, enable wildcard proxying on your CDN, or confirm the wildcard A record actually saved. Test with dig, not guesswork.

    Got a WordPress hosting or DNS question? Reply to this email—I cover one reader question every Sunday.