Author: onetwothreeadmin

  • AI content rewriting tools charge per output token—here’s the math

    AI content rewriting tools charge per output token—here’s the math

    AI content rewriting tools charge per output token—here's the math
    Photo by Emiliano Vittoriosi on Unsplash

    If you’re using AI to rewrite blog intros, tighten email copy, or rephrase social posts, you’re probably paying more than you think—and not because of sneaky upsells. Most AI rewriting tools charge based on output tokens, not input. That means the longer the rewritten version, the more you pay, even if you submitted three sentences.

    This isn’t obvious from the pricing pages. Tools like Jasper, Copy.ai, and Wordtune show monthly credit limits or character caps, but the actual burn rate depends on how verbose the AI gets. And if you’re feeding it prompts like “make this more engaging” or “expand this section,” you’re asking it to generate more words—which costs more.

    How token-based pricing works in practice

    Most AI tools use the same pricing model as the underlying APIs they’re built on—OpenAI, Anthropic, or Cohere. You pay per 1,000 tokens, where one token is roughly four characters or three-quarters of a word. Input tokens (what you send) are usually cheaper than output tokens (what the model generates).

    Here’s a real example: OpenAI’s GPT-4o charges $2.50 per million input tokens and $10 per million output tokens. If you submit a 200-word paragraph (roughly 270 tokens) and ask the model to rewrite it as a 400-word version (roughly 540 tokens), you’re billed for 270 input tokens and 540 output tokens. That’s $0.0007 for input and $0.0054 for output—about half a cent total.

    That sounds cheap. But if you’re rewriting 50 pieces of content per week, and each one generates 500 output tokens on average, you’re burning through 100,000 output tokens weekly—$1 per week, or $52 annually, just on output. And that’s if you’re using the API directly. Most third-party tools add a 3x to 10x markup.

    Jasper, for instance, doesn’t disclose token math on its pricing page. It shows credit limits. One “credit” might equal 100 words of output, but the actual cost depends on the model you’re using (GPT-4 vs. GPT-3.5) and how much it generates. If you run out of credits mid-month, you either upgrade or wait.

    When rewriting costs more than starting fresh

    The non-obvious cost isn’t the per-token rate—it’s the iteration trap. If you submit a draft, get a rewrite, then ask the AI to refine that rewrite, you’re doubling your output token spend. And if you’re doing this inside a tool like Copy.ai or Writesonic, each iteration burns another chunk of your monthly credit allotment.

    I’ve seen operators blow through a $49/month plan in two weeks because they were using AI to “polish” already-decent copy. The model would generate 800 words, they’d trim it to 400, then ask it to rewrite again. Each pass cost them output tokens they didn’t need to spend.

    Here’s the better workflow: draft in plain text, identify the one section that needs help, and submit only that section with a tight prompt. Instead of “make this better,” try “rewrite this paragraph in under 50 words, active voice, no fluff.” The tighter the constraint, the fewer output tokens the model generates.

    Track your burn rate before you commit

    If you’re paying for an AI rewriting tool, log into your account settings and check your usage dashboard. Most tools show credit consumption over the last 30 days. Divide that by the number of rewrites you ran. If you’re burning 10% of your monthly cap per session, you’ll hit the limit in ten sessions—not the “unlimited” rewrites the marketing page promised.

    For API users: OpenAI and Anthropic both offer usage dashboards that break down input vs. output token costs per request. If you’re spending more on output than input, you’re either generating long-form content (fine) or asking the model to expand short prompts into verbose responses (probably wasteful).

    The fix: add max token limits to your API calls. In OpenAI’s API, the max_tokens parameter caps output length. Set it to 150 if you want a short rewrite, 500 for a medium one. This keeps your costs predictable and forces the model to stay concise.

    When to skip the rewriting tool entirely

    If you’re rewriting fewer than 20 pieces of content per month, you don’t need a subscription tool. Use Claude or ChatGPT directly—both offer free tiers with generous limits, and paid plans ($20/month for ChatGPT Plus, $20/month for Claude Pro) give you flat-rate access with no per-token billing.

    Claude’s web interface is especially good for this. Paste your draft, ask for a rewrite, and iterate in the same conversation thread. The context window is large enough (200,000 tokens as of mid-2026) that you won’t hit limits unless you’re rewriting entire ebooks.

    For bulk rewriting—say, 100+ product descriptions or email subject lines—API access is cheaper than a SaaS subscription. Spin up a basic Python script, feed it a CSV of inputs, and batch-process rewrites. At $10 per million output tokens, you can rewrite 10,000 short sentences for around $5. No subscription, no credit caps.

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

    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.

  • Canva automation limits: how many scheduled posts you can queue

    Canva automation limits: how many scheduled posts you can queue

    Canva automation limits: how many scheduled posts you can queue

    Canva’s content planner feels unlimited when you start using it. Drag templates into a calendar, schedule posts across Instagram, Facebook, LinkedIn, and TikTok, and let the tool handle publishing. But after you queue 30, 50, or 100 posts, the interface starts behaving differently—and the documentation doesn’t tell you why.

    The limits exist. They’re soft caps tied to account type, platform mix, and post density. If you’re running a content-driven business that batches social creative a month in advance, you’ll hit them. Here’s how the system actually works.

    Queue depth varies by account tier

    Canva Free accounts can schedule roughly 8 posts at a time across all connected platforms. Canva Pro raises that to around 25–30 posts. Canva for Teams allows 100+ scheduled items, but the exact number fluctuates based on platform mix and whether posts include video.

    The caps aren’t documented in a help article with exact numbers. Support reps cite “fair use” and “platform stability,” which translates to: Canva doesn’t want free or low-tier users automating at scale. If you’re scheduling 60 Instagram posts and 40 LinkedIn updates in one sitting, expect the interface to block new additions after you cross the threshold.

    The error message is vague: “You’ve reached your scheduling limit. Try publishing some posts first.” No countdown. No tooltip. Just a soft block.

    Platform-specific limits layer on top

    Even within your account’s total queue cap, individual platforms enforce their own rules. Instagram allows 25 scheduled posts per connected profile. LinkedIn caps at 15. TikTok sits around 10. Facebook and Twitter (X) are more forgiving—closer to 50 each—but those numbers compress if you’re scheduling carousel posts, Reels, or video content.

    Video posts consume more of your queue budget than static images. A single TikTok video might count as two or three “slots” against your cap, especially if it’s longer than 60 seconds. Canva’s scheduler treats video processing as a heavier lift, so it rations how many you can queue simultaneously.

    If you’re using Publer or Buffer alongside Canva, you won’t hit these issues—those tools treat scheduling as a core feature and build infrastructure around high-volume queues. Canva treats scheduling as a convenience layer on top of design, so the architecture isn’t optimized for bulk automation.

    Workarounds when you hit the cap

    First: batch-publish older posts to free up slots. Go into your content calendar, find anything scheduled more than two weeks out, and either publish it immediately (if the timing isn’t critical) or delete it and re-add it later. The system only counts posts in the “scheduled” state, not drafts or published items.

    Second: stagger your scheduling sessions. Instead of queuing 60 posts on the first of the month, schedule 20 on the 1st, 20 on the 8th, and 20 on the 15th. The rolling queue window resets as posts publish, so spreading your scheduling across multiple sessions keeps you under the cap.

    Third: use Canva for design, then export and schedule elsewhere. Download your finished graphics as PNGs or MP4s, then upload them to a dedicated scheduler like Publer, Hootsuite, or Later. You lose the convenience of one-click scheduling, but you gain unlimited queue depth and better analytics.

    When to move off Canva’s scheduler entirely

    If you’re publishing more than 25 posts per week across multiple platforms, Canva’s planner becomes a bottleneck. The caps force you into manual queue management, and the lack of bulk-editing tools (you can’t shift 20 posts forward by three days in one action) makes calendar adjustments tedious.

    For operators running content-heavy brands—daily Instagram carousels, twice-daily LinkedIn commentary, scheduled Twitter threads—Canva works better as a design tool feeding into a real scheduling platform. Design in Canva, export to Publer or Buffer, and let the scheduler handle timing, recycling, and analytics rollup.

    Canva’s limits aren’t a deal-breaker if you’re posting 10–15 times per week. But if your workflow depends on batching a month of content in one session, the caps will force you to either upgrade to Teams (at $120/year for up to five users) or split your stack.

    Got a question about your own scheduling workflow? Reply to this email—I read every response and pull the best questions into future Q&A posts.

    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.

  • Stop treating every subscriber like a conversion target

    Stop treating every subscriber like a conversion target

    Stop treating every subscriber like a conversion target
    Photo by Morgan Housel on Unsplash

    The median online operator treats their subscriber list like a sales funnel with a timer attached. Every email becomes an opportunity to pitch, upsell, or extract. The logic sounds reasonable: you built the list to make money, so every touchpoint should drive toward a transaction.

    That approach works exactly once. Then it stops working, and you’re left wondering why open rates collapsed and unsubscribes spiked.

    The problem isn’t monetization. It’s the assumption that every subscriber, at every moment, exists in a buying state. They don’t. Most of your list is there for information, entertainment, or occasional utility—not to be sold to three times a week.

    The trust account model

    Think of subscriber attention as a bank account. Every useful email deposits credibility. Every pitch withdraws it. Send five valuable emails, you can afford one ask. Send three pitches in a row, and you’re overdrawn.

    Most operators never build a surplus. They treat launch day as withdrawal day, pitch affiliate offers before they’ve proven they understand the reader’s actual problems, or drop sponsorships into every issue because the CPM math says they should.

    The math doesn’t account for cumulative reader fatigue. A $400 sponsor slot this week might cost you six subscribers who would’ve bought your $200 course next quarter. You can’t measure what doesn’t happen, so you optimize for the wrong metric.

    What changes when you stop pitching

    I tracked two operators in the productivity-tool space last year—same niche, similar list size around 8,000 subscribers. One sent three emails per week with sponsor slots in every issue. The other sent two emails per week, sponsor-free, and pitched their own product once per month.

    Six months in, the sponsor-heavy operator had earned $11,200 in sponsorship revenue but saw list growth stall at 8,400 and open rates drop from 42% to 29%. The selective operator earned $9,800 from their own product, grew to 11,600 subscribers, and maintained 48% opens.

    The difference compounded. By month nine, the selective operator’s product revenue overtook the other’s total sponsorship income, because they had more engaged readers and higher conversion rates on the same offer.

    This isn’t anti-monetization. It’s pro-selectivity. Every pitch has a cost. If you’re not accounting for it, you’re flying blind.

    When to actually ask

    Three conditions make a pitch worth the trust withdrawal:

    You’ve recently solved a problem for them. If your last three emails helped someone fix a workflow issue, speed up their site, or understand a confusing tool feature, they’re primed to hear about a related product. The ask feels like a natural extension, not an interruption.

    The offer is narrowly relevant. Broad pitches (“check out this course on online business”) perform worse than specific ones (“if last week’s email on SEO title tags was useful, this guide covers the 14 other on-page factors that move rankings”). Relevance isn’t about your niche—it’s about the exact problem you just addressed.

    You’re willing to skip the next two pitches. If you can’t afford to go silent on monetization for two weeks after an ask, you’re over-extracting. The readers who didn’t buy need time to forget the sales pressure before you ask again.

    The operators who get this right

    The best-performing lists I’ve seen run 5:1 or 6:1 ratios—five or six pure-value emails for every monetization attempt. They treat pitches like they’d treat asking a favor from a friend: sparingly, with context, and only when the relationship can handle it.

    That doesn’t mean waiting months to monetize. It means being deliberate. If you publish daily, you can pitch weekly and still maintain a healthy ratio. If you publish weekly, maybe you pitch monthly, or you build a small sponsorship into your standard format but keep it consistent and predictable rather than varied and aggressive.

    The goal isn’t to avoid revenue. It’s to avoid the revenue plateau that comes from burning through trust faster than you rebuild it.

    Want more operator-to-operator breakdowns like this? Subscribe to One Two Three Send for weekly tactics on running a content business without the generic advice.

  • WordPress page caching: when dynamic content breaks static delivery

    WordPress page caching: when dynamic content breaks static delivery

    WordPress page caching: when dynamic content breaks static delivery
    Photo: Rami via Wikimedia Commons (Public domain)

    Page caching is one of the fastest ways to speed up a WordPress site. Instead of rebuilding every page on every visit, the server delivers a static HTML snapshot. For content-driven sites, it’s a performance multiplier—until it breaks something you didn’t realize was dynamic.

    The promise is simple: cache the page once, serve it to everyone. The problem is that “everyone” includes logged-in users, people in different time zones, and visitors who should see personalized content. When you turn on full-page caching without understanding what gets frozen, you end up serving stale data to the wrong people.

    What page caching actually does

    Most caching plugins—WP Rocket, LiteSpeed Cache, W3 Total Cache—generate a static HTML file the first time someone visits a page. Every subsequent visitor gets that file until it expires or you manually clear the cache. The PHP engine never runs. The database never gets queried. It’s fast because it skips WordPress entirely.

    That works fine for a blog post that doesn’t change. It breaks the moment you add anything that should look different for different visitors: a “Welcome back, [Name]” message, a shopping cart count, a members-only section, a countdown timer, or even a “currently online” widget.

    The static HTML file doesn’t know who’s visiting. It shows the same cached snapshot to everyone—logged in or not, subscriber or guest, New York or Tokyo.

    What breaks first

    The most common casualties are widgets and sidebar elements that rely on server-side state. A “recent comments” block might show the same five comments for hours, even as new ones come in. A “popular posts” widget freezes at whatever was popular when the cache was built. If you’re running ads or affiliate content that rotates server-side, the same banner gets served to everyone until the cache clears.

    Logged-in users see the logged-out version of the page unless you explicitly exclude them from caching. That means no admin bar, no edit links, no personalized menus. If you’re running a membership site or a course platform, this is a deal-breaker. Members land on a page that tells them to log in, even though they already are.

    Checkout pages, account dashboards, and cart views also break under full-page caching. Most plugins auto-exclude /cart/ and /checkout/ paths, but if you’re using a custom URL structure or a non-standard plugin, you need to add exclusions manually.

    How to cache without breaking dynamic content

    The cleanest fix is to separate static and dynamic elements. Cache the page structure—header, footer, main content—and load personalized pieces via JavaScript after the page renders. Most modern membership plugins and ecommerce platforms do this by default: the page loads instantly from cache, then an AJAX call fetches the cart count or user name and injects it into the DOM.

    If you’re building custom features, use the same pattern. Cache the full page, but add a data-user-id attribute to any personalized container and populate it client-side with a lightweight API call. Keep that endpoint uncached—exclude /wp-json/ routes or use a dedicated AJAX handler.

    For logged-in users, most caching plugins offer a “don’t cache for logged-in users” toggle. Enable it if your site has frequent admin activity or if subscribers expect personalized views. The trade-off is that logged-in traffic bypasses the cache entirely, so page speed drops for those visitors. If you have a small team and most traffic is anonymous, this is fine. If half your visitors are logged in, you’re losing most of the performance benefit.

    Time-sensitive content—countdowns, limited offers, live event notices—should either be excluded from caching or rendered client-side. A cached page with a countdown timer will show the same time to everyone until the cache expires, which defeats the urgency. Use JavaScript to calculate the time difference in the browser, or exclude the page from caching and accept the performance hit.

    Testing what actually gets cached

    The easiest way to catch caching issues before they go live: visit your site in an incognito window, clear the cache, reload the page, then log in and reload again. If the logged-in view looks identical to the logged-out view, something’s wrong. Check the page source—if you see on a logged-in page, you need to adjust your exclusion rules.

    Most caching plugins log which pages get cached and which get bypassed. WP Rocket and LiteSpeed Cache both show cache hit/miss stats in their dashboards. If a checkout page shows a cache hit, you know it’s misconfigured.

    For membership sites, test with a subscriber account. Log in, navigate to a members-only page, then open the same URL in a private window. If the private window shows the member content, the page was cached while you were logged in and is now being served to everyone. Add that path to your exclusion list immediately.

    Page caching is worth the setup cost—most WordPress sites see 40–60% faster load times once it’s configured correctly. But if you ship personalized content, ecommerce, or logged-in experiences, the default settings will break something. Test every dynamic element, exclude what needs to stay fresh, and move the rest to client-side rendering.

    Got a caching setup that works for your WordPress site? Reply and let us know which plugin you’re using and how you handle logged-in users—we’ll feature the best setups in a future roundup.

  • Social media APIs throttle embeds differently than timeline requests

    Social media APIs throttle embeds differently than timeline requests

    Social media APIs throttle embeds differently than timeline requests
    Photo by Adem AY on Unsplash

    If you’ve ever built a site that pulls in social media content—testimonials from Twitter, Instagram feed widgets, YouTube video metadata—you’ve probably hit a rate limit at some point. What’s less obvious is that most platforms separate their rate limits by endpoint type, and embeds get treated very differently than timeline or profile requests.

    This matters because the failure modes aren’t the same. A timeline request that hits a rate limit usually returns a 429 status and a retry-after header. An embed request might return a cached fallback, a blank card, or—on some platforms—no error at all, just stale data.

    How platforms split rate limits

    Twitter’s API (now X) has separate buckets for /statuses/show (single tweet lookup, used by oEmbed), /statuses/user_timeline, and /search/tweets. If you’re on the free tier in 2026, you get 500 tweet lookups per month and 1,500 timeline requests. Embed a popular tweet on your homepage that gets 10,000 visits a day? You’ll burn through your embed quota in under an hour, but your timeline widget might still work fine.

    Instagram’s API treats embeds through the oEmbed endpoint separately from the Graph API used for pulling your own feed. The oEmbed endpoint is more permissive—no auth required—but it’s also cached aggressively on Instagram’s side. If you’re embedding a post that’s been deleted or made private, you might still see it rendered for hours because Instagram’s CDN hasn’t invalidated the embed yet.

    YouTube separates video metadata requests (used by oEmbed and the Data API) from channel or playlist requests. The Data API has a quota system measured in units, and a single video details request costs 1 unit, while a search costs 100. Embedding a video costs almost nothing; searching for videos to embed costs a lot.

    When embeds fail silently

    The worst case isn’t a 429 error—it’s when the embed keeps working but shows outdated content. Facebook’s oEmbed endpoint caches post data for up to 24 hours. If someone updates a post you’ve embedded, your site won’t reflect it until Facebook’s cache expires. There’s no manual purge option for third-party embeds.

    Twitter’s embed.js script fetches the rendered HTML client-side after page load. If the tweet’s been deleted, you’ll see a blank space or a “this tweet is unavailable” message—but only after the JavaScript loads and tries to hydrate the embed. Server-side rendering won’t catch this; your HTML will still contain the embed markup, and it’ll look fine until the browser tries to fetch the actual content.

    LinkedIn doesn’t offer a public oEmbed API at all anymore. If you’re embedding LinkedIn posts, you’re either using an unofficial scraper (which will break when LinkedIn changes their HTML structure) or you’re embedding a static screenshot. Neither approach respects rate limits because there’s no API to rate-limit in the first place.

    How to design around this

    If you’re embedding social content dynamically—testimonials, recent posts, social proof—build in a fallback that doesn’t depend on the API being available. Cache the embed HTML server-side with a TTL that matches the platform’s cache duration (24 hours for Facebook, 7 days for Twitter). Serve the cached version by default, and refresh it in the background on a slower schedule than your page views.

    For high-traffic pages, pre-render embeds at build time instead of fetching them on every request. If you’re using a static site generator, fetch the oEmbed data during the build step and store the HTML in your repo. You’ll avoid rate limits entirely, though you’ll need to rebuild when you want fresh content.

    If you’re embedding third-party content—user-generated tweets, Instagram posts from customers—don’t rely on real-time embeds. Fetch the content once when the user submits it, store the rendered HTML or a screenshot, and display that. If the original post gets deleted or rate-limited later, your page still works.

    Monitoring rate limit usage

    Most platforms include rate limit headers in their API responses: X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset. Log these when you make requests, especially for embeds that fire frequently. You’ll see when you’re close to a limit before you hit it.

    Twitter’s API dashboard shows rate limit usage per endpoint, but only if you’re using OAuth. Anonymous oEmbed requests—common for public embeds—don’t show up in your dashboard. You’ll only know you’ve hit the limit when embeds stop loading.

    YouTube’s quota usage appears in the Google Cloud Console under “APIs & Services.” If you’re embedding videos on multiple sites, they all share the same project quota unless you’ve set up separate API keys. One site hitting the limit will throttle all your other sites until the quota resets at midnight Pacific time.

    If you’re running a content site that embeds social posts frequently, set up alerting when your rate limit remaining drops below 20%. That gives you time to switch to cached embeds or disable dynamic loading before your pages start breaking.

    What are you embedding, and how often does it break? Reply and let us know what rate limits you’ve hit—or if you’ve found a workaround that works better than caching.

  • SEO keyword cannibalization: when it happens and how to fix it

    SEO keyword cannibalization: when it happens and how to fix it

    SEO keyword cannibalization: when it happens and how to fix it
    Photo by NisonCo PR and SEO on Unsplash

    You publish a guide on email segmentation in January. It ranks on page two. In March, you write another post about segmentation tactics. Google starts showing the new one instead—but now both hover around position 15–20, and neither breaks page one.

    That’s keyword cannibalization: when multiple pages on your site compete for the same search intent, Google can’t pick a clear winner, and your ranking power gets diluted across both.

    It’s more common than most solo operators realize, especially if you’ve been publishing consistently for a year or more. Here’s how to spot it, decide what to merge or redirect, and execute the fix without tanking your existing traffic.

    How to find cannibalization on your site

    Open Google Search Console. Navigate to Performance, then add a Query filter for a term you know you’ve written about multiple times—something like “email subject lines” or “WordPress caching.”

    Click into the query. Scroll to the Pages tab. If you see two or more URLs getting impressions and clicks for the same keyword, and their average positions are similar (both around position 8–15, for example), that’s a cannibalization signal.

    The clearer test: search Google directly for site:yoursite.com "your keyword". If three or four posts appear, all covering roughly the same angle, you’ve got overlap.

    Not every overlap is a problem. If one page ranks position 3 and another ranks position 47, that’s fine—the lower one isn’t stealing anything. Cannibalization matters when both pages are stuck in the same mid-tier range and neither can break through.

    Merge, redirect, or reposition

    Once you’ve identified cannibalized pages, you have three options.

    Merge and redirect. Take the better-performing URL (higher clicks, better backlinks, or older publish date) and fold the content from the weaker page into it. Update the stronger post with any useful material from the weaker one, then set up a 301 redirect from the weaker URL to the consolidated page. This passes link equity and tells Google there’s now one clear answer.

    Redirect without merging. If one post is clearly superior and the other adds nothing new, just redirect the weaker one. No need to bloat the winner with redundant paragraphs.

    Reposition one page for a different keyword. If both posts have value but target overlapping intent, rewrite one to focus on a distinct angle. For example, split “email segmentation” into “email segmentation for e-commerce” and “behavioral segmentation tactics.” Update titles, H2s, and meta descriptions to clarify the difference. Internal links should reflect the new distinction.

    Most operators default to option three because deleting content feels risky. But in practice, merging and redirecting usually produces faster ranking gains. Google rewards clarity.

    What happens after you redirect

    Rankings don’t update instantly. Expect a 2–4 week lag while Google recrawls the redirected URL, consolidates signals, and re-evaluates the surviving page.

    During that window, you might see both pages drop slightly before the consolidated one climbs. That’s normal. If the merged page hasn’t recovered within 30 days, check that the redirect is live (test it in an incognito browser), that the new page actually covers the topic comprehensively, and that you didn’t accidentally noindex it.

    Track the consolidated page in Search Console. Filter by the target query and watch position and impressions over the next month. If you picked the right survivor and the content is strong, you should see a 5–15 position jump within six weeks.

    When to leave duplicates alone

    Not every topical overlap needs fixing. If you run a newsletter with weekly tips and occasionally touch the same subject in different contexts—say, a how-to guide and a case study—that’s fine. Different content types satisfy different intents.

    Cannibalization is a problem when the search intent is identical and Google sees no reason to prefer one page over the other. If one page is a tutorial and another is a tool comparison, even if they mention the same keyword, they’re not cannibalizing.

    The test: would a searcher clicking one page feel like the other is redundant? If yes, merge. If no, leave them.

    Found cannibalization on your site? Reply with the query and competing URLs—I’ll tell you which one to keep.

  • Newsletter preview text: what gets truncated and when it matters

    Newsletter preview text: what gets truncated and when it matters

    Newsletter preview text: what gets truncated and when it matters
    Photo: Unknown via Wikimedia Commons (Public domain)

    Preview text—the snippet that appears below your subject line in most email clients—gets truncated at wildly different lengths depending on where your subscriber opens it. Gmail on desktop shows roughly 100 characters. Outlook on Windows cuts off around 40. Apple Mail on iPhone displays up to 140 in portrait mode, less in landscape.

    Most newsletter operators write preview text once and assume it renders consistently. It doesn’t. And because preview text directly influences open rates (some studies peg the lift at 8–12% when optimized), understanding how truncation works matters more than you’d expect.

    Where the cuts happen

    Desktop clients are the most forgiving. Gmail shows approximately 100 characters on a typical monitor width. Apple Mail on macOS displays around 90. Outlook 2019 and 2021 on Windows cut hard at 40–50 characters, depending on subject line length—they share a fixed pixel width, so a long subject line eats into preview space.

    Mobile is tighter. Gmail’s mobile app shows 80–90 characters in portrait, less in landscape. Apple Mail on iPhone displays up to 140 characters in portrait but drops to 70–80 in landscape. Outlook mobile sits around 65 characters regardless of orientation.

    The problem: if your key message or call-to-action lives past character 50, roughly 30–40% of your list won’t see it. Outlook desktop users and anyone reading in landscape mode get cut off mid-sentence.

    Frontloading vs. padding

    The common advice is to frontload value—put your hook, offer, or call-to-action in the first 40 characters. That works when you have a single, clear message. “Early access ends Friday” or “Three new case studies inside” fit cleanly.

    But frontloading creates a new problem: preview text that repeats your subject line. If your subject is “Case studies: how three operators doubled revenue” and your preview is “Three new case studies inside,” you’ve wasted 30 characters saying the same thing twice. Subscribers who do see the full preview get redundancy instead of context.

    A better approach: use preview text to extend or qualify the subject line, but assume only the first 40–50 characters will render universally. Structure it so the opening phrase stands alone, and anything past character 50 adds detail for clients that display more.

    Example: Subject line is “Affiliate link cloaking breaks in three places.” Preview text could be “DNS propagation, cache headers, redirect chains—here’s how to test each one.” The first phrase (“DNS propagation, cache headers, redirect chains”) gives context even when truncated. The second half (“here’s how to test each one”) adds value for subscribers on longer-display clients, but the preview still works without it.

    Testing across clients

    Most ESPs show a preview-text field in the send interface, but they don’t simulate truncation accurately. Beehiiv, MailerLite, and ConvertKit all display your full preview text in the editor—you won’t see how it renders on Outlook mobile until you send a test.

    The best workflow: send test emails to multiple addresses on different clients before publishing. At minimum, check Gmail desktop, Apple Mail on iPhone, and Outlook on Windows. If you’re running a paid newsletter or sending to a B2B audience, add Outlook mobile to the rotation—corporate subscribers skew heavily toward Microsoft clients.

    For operators sending daily or multiple times per week, set up a permanent test list with addresses tied to each major client. Send every issue to that list five minutes before the main send. Open each one, screenshot the inbox view, and compare truncation points. It takes three minutes and catches preview-text issues before they hit your full list.

    When preview text doesn’t matter

    Preview text has diminishing returns in three scenarios. First: if your open rates are already above 50%, you’re likely serving a highly engaged list that opens based on sender name and subject line alone. Optimizing preview text might add a percentage point or two, but it’s not your leverage point.

    Second: transactional emails. Password resets, order confirmations, and receipt emails get opened regardless of preview text. If you’re using Postmark or a dedicated transactional service, default preview text (often the first line of body copy) works fine.

    Third: emails where the subject line is self-contained and actionable. “Your invoice is ready” or “You’re confirmed for Friday’s workshop” don’t need preview-text reinforcement. Adding “Click here to download” or “See you at 2pm ET” is redundant.

    Preview text matters most when your subject line raises a question or teases value without fully delivering it. If the subject is “Three underused features in your analytics dashboard,” preview text like “Session replay, funnel drop-off alerts, and cohort comparison—most operators miss all three” gives just enough detail to justify the open.

    Want breakdowns like this in your inbox? Subscribe to One Two Three Send for operator-focused deep dives on the tools and tactics that actually move your online business forward.

    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.

  • Three ways affiliate link cloaking breaks and how to test it

    Three ways affiliate link cloaking breaks and how to test it

    Three ways affiliate link cloaking breaks and how to test it
    Photo by GuerrillaBuzz on Unsplash

    Affiliate link cloaking sounds simple: turn an ugly tracking URL into something clean, track the click, redirect the visitor. But redirects are fragile infrastructure, and most operators don’t test them until someone mentions a broken link in a reply.

    Cloaking breaks in three predictable ways. If you’re running affiliate links through a WordPress plugin, a custom subdomain, or a link-management service, you’ve probably hit at least one of these.

    The plugin update that changes redirect logic

    Most WordPress affiliate plugins—Pretty Links, ThirstyAffiliates, Lasso—handle redirects by intercepting requests at the PHP level. When the plugin updates, redirect logic can shift. A 301 permanent redirect might become a 302 temporary. A direct redirect might add an intermediate JavaScript step for click tracking.

    The symptom: your affiliate dashboard shows zero clicks, but Analytics shows traffic landing on the cloaked URL. The redirect fired, but the tracking layer didn’t log it—or vice versa.

    Test it: after every plugin update, open an incognito window and click one of your cloaked links. Watch the browser’s network tab (right-click > Inspect > Network). You should see a single 301 or 302 response pointing to the affiliate URL, with no intermediate stops. If you see a 200 response or multiple hops, something changed.

    Non-obvious fix: most plugins let you choose redirect type. Set it to 301 unless you’re actively A/B testing destinations. Temporary redirects (302, 307) tell browsers and crawlers not to cache the destination, which means more server load and slower clicks.

    The subdomain DNS record that expires

    Some operators run cloaked links on a subdomain—go.yourdomain.com or link.yourdomain.com—to keep affiliate URLs off the root domain. This requires a DNS A or CNAME record pointing the subdomain to your server.

    If you’re using a CDN or a hosting provider that rotates IP addresses, that DNS record can go stale. The subdomain resolves to an old IP, the redirect doesn’t fire, and the visitor sees a generic server error or a parked-domain page.

    This happens most often after migrating hosts or switching CDN providers. The root domain updates automatically because your registrar’s nameservers handle it. The subdomain doesn’t, because it’s a manual DNS entry you set once and forgot about.

    Test it: run nslookup go.yourdomain.com in your terminal (or use an online DNS lookup tool). Compare the returned IP to your current server’s IP. If they don’t match, update the A record. If you’re behind a CDN like Cloudflare, the CNAME should point to the CDN’s endpoint, not your origin server.

    Non-obvious fix: set a calendar reminder every 90 days to verify subdomain DNS records. Most hosts don’t send alerts when an A record points to a decommissioned IP—they assume you know what you’re doing.

    The browser privacy feature that blocks redirects

    Safari’s Intelligent Tracking Prevention and Firefox’s Enhanced Tracking Protection treat some redirects as tracking attempts and block them silently. If your cloaked link lands on a known affiliate domain (impact.com, shareasale.com, cj.com), the browser may strip tracking parameters or refuse to follow the redirect at all.

    The visitor sees your cloaked URL in the address bar, but the page doesn’t load. No error message. Just a blank screen or a “page took too long to respond” timeout.

    This isn’t theoretical. A reader running Safari 17 or later with default privacy settings will hit this on roughly 15–20% of affiliate networks, depending on how the network structures its tracking URLs.

    Test it: open Safari (or Firefox with Enhanced Tracking Protection set to Strict). Click your cloaked link. If the redirect doesn’t fire within two seconds, the browser blocked it. Check the browser console (Develop > Show JavaScript Console in Safari)—you’ll see a message about “prevented a redirect” or “blocked a tracker.”

    Non-obvious fix: some affiliate networks offer “privacy-friendly” tracking URLs that use first-party cookies instead of third-party parameters. Ask your affiliate manager if they have a Safari-compatible link format. If not, consider disclosing the redirect in your link text (“this link redirects to [Brand]”) so visitors know what to expect if the browser blocks it.

    How to catch breaks before they cost you

    Set up a monthly check: pick five high-traffic affiliate links and test them in Chrome (incognito), Safari (default privacy settings), and Firefox (Strict mode). Log the results in a spreadsheet with the date, the cloaked URL, the destination URL, and whether the redirect fired in each browser.

    If a link breaks, you’ll know which browser triggered it and when. Most breaks happen within 48 hours of a plugin update, a DNS change, or a hosting migration—events you can correlate with the test date.

    One more thing: if you’re using a link-management service like Bitly or Rebrandly for affiliate cloaking, check their status page once a quarter. These platforms occasionally retire redirect infrastructure or change how they handle affiliate domains. They’ll announce it in a changelog you probably don’t read. The first symptom is a spike in 404s on links that worked last week.

    Want more operator tactics like this? Subscribe to One Two Three Send for weekly breakdowns of the tools and workflows that actually matter when you’re running a content business solo.

  • AI assistants forget mid-conversation—here’s what triggers it

    AI assistants forget mid-conversation—here’s what triggers it

    AI assistants forget mid-conversation—here's what triggers it
    Photo by Cody Engel on Unsplash

    You’re three hours into a research session with an AI assistant. You’ve fed it your product brief, customer interview notes, and a draft outline. You ask it to refine the intro based on everything you’ve discussed. It responds with something generic—like it never saw any of your earlier messages.

    You didn’t do anything wrong. The assistant just ran out of memory.

    Context windows have hard limits

    Every AI model has a maximum context window—the total number of tokens (roughly words and punctuation) it can hold in a single conversation. For Claude, that’s 200,000 tokens on the Sonnet and Opus models. For GPT-4o, it’s 128,000. Once you exceed that limit, the model starts dropping the oldest messages to make room for new ones.

    A token isn’t exactly a word. Short words like “it” or “to” are single tokens. Longer words like “conversation” might be two or three. Punctuation, formatting, and code add up faster than you expect. A 1,000-word document is usually around 1,300 tokens. A 10-message back-and-forth with code snippets and formatting can easily hit 5,000.

    If you’re working in a long session—drafting email sequences, debugging workflows, refining a landing page—you can hit the limit without realizing it. The assistant doesn’t warn you. It just starts forgetting.

    What gets dropped first

    Most models use a sliding window. When the conversation exceeds the token limit, the system drops the oldest user and assistant messages first, but keeps the system prompt and the most recent exchanges. That means the assistant remembers what it’s supposed to do (your initial instructions), but not why you made certain decisions earlier in the session.

    This is why an assistant might contradict itself after a long thread. It still knows it’s helping you write a welcome sequence, but it no longer remembers that you explicitly rejected a friendly tone in message twelve.

    Some platforms handle this better than others. Claude‘s Projects feature lets you pin reference material—brand guidelines, product specs, style rules—so it doesn’t count against the per-conversation limit. That buys you more room for the actual back-and-forth. If you’re using the standard chat interface, though, everything counts.

    How to structure prompts so you don’t lose context

    The simplest fix: start a new conversation before you hit the limit. If you’re working on a complex project, break it into discrete sessions. Draft the outline in one chat. Write the first section in another. Edit in a third. Paste the relevant output from the previous session into the new one as reference material.

    It’s more manual, but it forces you to compress and curate what the assistant actually needs to remember. Instead of a 50-message thread where half the exchanges are clarifications and dead ends, you give it a clean summary and move forward.

    If you need to preserve context across a long session, front-load your instructions. Put your brand voice, audience details, and key constraints in the first message. If the model starts forgetting, it’ll drop the middle of the conversation first—your initial setup stays intact longer.

    Another option: export the conversation transcript periodically and save it as a text file. If the assistant loses context, you can paste relevant sections back in as a reminder. It’s not elegant, but it works when you’re deep in a research or drafting session and don’t want to start over.

    When to check token usage

    Most AI platforms don’t surface token counts prominently. Claude’s interface shows approximate usage if you hover over certain UI elements, but it’s not always visible. The OpenAI Playground displays token counts directly; the ChatGPT web interface does not.

    If you’re using the API, you can track tokens in the response metadata. For the web interfaces, assume that any conversation longer than 30 back-and-forth messages is approaching limits—especially if you’re pasting documents, code, or formatted text.

    A rough heuristic: if you’ve scrolled more than three screen heights in a single conversation, consider starting fresh or summarizing.

    The platform doesn’t owe you a warning. Token limits are documented, but the interface won’t stop you from continuing a conversation that’s functionally useless because the model can’t remember the beginning. It’ll keep responding. It just won’t be accurate.

    If you’re running into this regularly, reply and tell us what you’re working on. We’re cataloging the specific workflows where context limits cause the most friction—and which tools handle it best.

    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.

  • Google Analytics 4 session timeout: what 30 minutes actually measures

    Google Analytics 4 session timeout: what 30 minutes actually measures

    Google Analytics 4 session timeout: what 30 minutes actually measures
    Photo: Saleemkce via Wikimedia Commons (CC BY-SA 4.0)

    Google Analytics 4 ends a session after 30 minutes of inactivity by default. Most operators know that number, but fewer understand what the timer actually tracks—or how changing it affects every engagement metric in your dashboard.

    If you’re running a content site, newsletter archive, or documentation hub where readers spend time away from the tab, the standard timeout can fragment what should count as a single visit. Here’s how the mechanism works and when to adjust it.

    How the 30-minute timer starts and resets

    GA4 starts a session the moment someone lands on your site and fires the first pageview or event. The 30-minute countdown begins immediately. Every subsequent interaction—pageview, scroll, click event, video play—resets the timer back to zero.

    If someone reads an article for twelve minutes, opens a new tab to check email for eight minutes, then returns to click a link, GA4 sees continuous activity. The session persists because the gap never hit thirty minutes.

    But if that reader leaves the tab open, walks away for thirty-one minutes, then comes back and scrolls, GA4 registers a new session. Same browser, same tab, different session. That split changes your session count, pages-per-session average, and engagement rate.

    The timer is client-side and local to the browser. It doesn’t sync across devices. If someone starts reading on mobile during a commute and picks up the same article on desktop an hour later, those are always separate sessions—even if they’re logged in.

    When the default timeout distorts your metrics

    Thirty minutes works well for ecommerce and SaaS dashboards where sessions map to discrete tasks: browse products, compare plans, check out. Gaps longer than half an hour usually signal a different intent or context.

    Content sites see different behavior. A reader might open five tabs from your homepage, read each article for eight minutes over the course of an hour, and trigger five separate sessions because the gaps between tab switches exceeded the threshold.

    Documentation sites and tutorial hubs get hit hardest. Readers toggle between your guide and their own project. A thirty-minute threshold treats a single problem-solving session as three or four visits, deflating engagement time and inflating bounce rate.

    If your average GA4 session duration is under two minutes but you publish 10-minute reads, the timeout setting is likely splitting real reading sessions into fragments.

    Adjusting the session timeout in GA4

    You can change the session timeout in GA4’s data stream settings. Navigate to Admin → Data Streams → [your stream] → Configure tag settings → Adjust session timeout. The range is 1 to 120 minutes for inactivity timeout.

    Extending it to 60 or 90 minutes makes sense if your content encourages multi-tasking or requires readers to step away and return. Shortening it to 15 minutes can help if you want tighter attribution windows for fast-moving campaigns or live events.

    Changing the timeout doesn’t backfill historical data. GA4 applies the new setting only to sessions that start after you save the change. If you’re comparing month-over-month engagement metrics and you adjusted the timeout mid-period, your averages will be skewed.

    One non-obvious side effect: increasing session timeout also extends the window for attributing conversions to the original traffic source. If someone arrives from organic search, reads for twenty minutes, leaves for forty, then returns and subscribes, a 30-minute timeout attributes that conversion to direct traffic. A 60-minute timeout keeps the organic attribution intact.

    When not to change it

    If you’re running paid campaigns or affiliate tests and need to compare performance across tools, keep GA4’s timeout at the default. Most ad platforms and attribution tools assume a 30-minute session window. Diverging from that standard makes cross-platform reporting harder to reconcile.

    Similarly, if you’re part of a media network or benchmark group that shares analytics data, non-standard timeout settings make your engagement metrics incomparable. A 90-minute timeout will always show higher pages-per-session than a peer using 30 minutes, even if actual behavior is identical.

    And if your content is truly short-form—tweet threads, quick-hit news briefs, recipe cards—a longer timeout just adds noise. Sessions that stretch across an hour when your median read time is ninety seconds don’t reflect real engagement; they reflect open tabs.

    The default exists for a reason: it works for most sites most of the time. But if your engagement metrics don’t align with how readers actually use your content, the session timeout is one of the first settings worth testing.

    Want more analytics breakdowns like this? Subscribe to One Two Three Send for weekly deep-dives on the tools and settings that shape your business metrics.