Author: onetwothreeadmin

  • AI assistants leak context when you switch between projects

    AI assistants leak context when you switch between projects

    If you’re using ChatGPT, Claude, or Gemini to draft emails, write product descriptions, and brainstorm content ideas in the same session, you’ve probably noticed the tone starting to bleed. A client brief starts sounding like your newsletter. Your course outline picks up jargon from a product spec you wrote an hour ago.

    That’s not you losing focus. It’s the assistant remembering too much.

    How AI memory works across conversations

    Most conversational AI tools maintain context within a single chat thread. That’s useful when you’re iterating on a draft or debugging a workflow. But many platforms now also persist memory across threads—storing facts, preferences, and patterns from past sessions to make future responses feel more tailored.

    ChatGPT’s memory feature, for example, stores details like your writing style, preferred tools, and recurring projects. Claude offers a similar feature called “custom instructions” that carries forward between chats. Gemini ties memory to your Google account, pulling in context from Gmail, Docs, and prior conversations.

    The problem: these tools don’t automatically segment memory by project, client, or business vertical. If you’re a solo operator juggling freelance work, your own newsletter, and a side product, the AI treats it all as one continuous job.

    That means a prompt like “write a welcome email” might generate copy that sounds like the SaaS client you were working with yesterday—not the D2C product you’re launching today.

    When bleed happens and why it matters

    Context bleed shows up most clearly in tone, vocabulary, and assumed audience. If you’ve been drafting B2B landing pages all morning and then ask the AI to write a casual Twitter thread, you’ll often get something that splits the difference: too formal for social, too chatty for a white paper.

    It’s worse when you’re working under NDA or handling sensitive client material. Even if you’re not pasting in proprietary data, the AI might pick up on industry-specific language, product names, or strategic framing and echo it back in unrelated work. That’s a compliance risk and a professionalism problem.

    For operators running multiple revenue streams—affiliate content, a paid newsletter, consulting, a course—context bleed also dilutes your brand. Your newsletter starts to sound like your client’s voice. Your course copy picks up affiliate-review phrasing. Readers notice when the tone shifts, even if they can’t articulate why.

    How to isolate context without losing efficiency

    The simplest fix: use separate chat threads for separate projects. Don’t rely on the AI to infer boundaries. Start a fresh conversation every time you switch contexts.

    If your AI tool supports memory or custom instructions, turn it off for client work. In ChatGPT, you can disable memory in settings under “Data Controls.” Claude lets you clear custom instructions per chat. Gemini’s memory is harder to partition, but you can use incognito mode or a separate Google account for client sessions.

    For operators who bill multiple clients or run distinct content verticals, consider using different AI accounts entirely. A free-tier ChatGPT account for client drafts, a paid Claude subscription for your own content. It’s redundant, but it enforces a hard boundary.

    Another tactic: explicitly reset context in your prompt. Start each session with a short instruction that overrides prior memory. Something like: “Forget previous projects. This is a cold email for a B2C e-commerce brand selling outdoor gear. Tone: direct, benefit-focused, no jargon.” It’s not foolproof, but it reduces bleed.

    When memory is worth keeping

    Context persistence isn’t inherently bad. If you’re working on a single long-term project—building out a course, drafting a book, developing a content calendar—memory helps the AI stay consistent without you having to repeat background in every prompt.

    The key is intentional segmentation. Treat AI memory like browser cookies: useful within a defined scope, risky when it leaks across domains.

    If you’re a solo operator, that means thinking through which projects share a voice and which need to stay isolated. Your newsletter and your Twitter threads? Probably fine to share context. Your newsletter and a white-label ghostwriting gig? Keep those separate.

    Most AI tools don’t yet offer project-level memory management. Until they do, the burden is on you to create those boundaries manually—through new threads, separate accounts, or hard resets in your prompts.

    One Two Three Send covers AI tools, workflow automation, and the infrastructure that keeps solo operators running. If this kind of tactical breakdown is useful, subscribe for one article like this every day.

    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.

  • Notion databases: when to relate tables and when to duplicate

    Notion databases: when to relate tables and when to duplicate

    Notion sells itself on the promise of connected databases—one source of truth, relational properties, rollups that calculate automatically. It’s a compelling pitch, especially if you’re managing clients, projects, content calendars, and invoices in the same workspace.

    But relational databases in Notion come with friction most solo operators don’t anticipate until they’re neck-deep in broken views and slow-loading pages. Sometimes the smarter move is to duplicate your data instead of relating it.

    When relations make sense

    Relational properties work well when you need live, two-way sync between databases. A classic example: a Projects database linked to a Clients database. You relate each project to a client, and Notion automatically shows all projects under that client’s page. Add a rollup, and you can calculate total hours billed or outstanding invoices without touching a spreadsheet.

    This setup shines when:

    • You frequently filter or group by the related property (e.g., “show me all active projects for Client X”).
    • The related database is relatively small—under 500 rows.
    • You need rollups or formulas that pull data from the related table.

    But the moment your related database grows past a few hundred entries, or you start chaining relations (Projects → Clients → Invoices → Line Items), Notion’s performance starts to sag. Pages take three to five seconds to load. Inline databases stutter when you apply filters. Mobile becomes nearly unusable.

    When duplication beats relation

    Duplication means copying static data—like a client name or project status—directly into the database where you need it, rather than linking to another table. You lose the automatic sync, but you gain speed and simplicity.

    Here’s when to duplicate:

    • High-volume databases. If your content calendar has 1,000+ rows and you’re relating each post to an author database, every view recalculates those links. Duplicating the author name as plain text makes filters instant.
    • Archival data. If you’re logging completed projects or past invoices, the data rarely changes. A relation adds complexity with no upside—just copy the client name and close the loop.
    • Cross-workspace collaboration. Notion’s database relations don’t work across workspaces. If you’re sharing a content calendar with a client but keeping your internal project tracker private, duplication is your only option.

    Yes, you lose the ability to update a client’s name in one place and see it cascade everywhere. But for most solo operators, that’s a theoretical problem. You’re not renaming clients every week. The performance gain is real; the sync risk is hypothetical.

    The hybrid approach

    You don’t have to choose one strategy for your entire workspace. I run a Content database with 800+ posts. Each post has a Topic property—but instead of relating to a separate Topics database, I use a multi-select dropdown. It’s technically duplication (the topic name lives in the Content database), but I can still filter, group, and count posts by topic without the relational overhead.

    For high-touch workflows—like tracking sponsorship deals where I need live rollups of total contract value—I keep the relation. For everything else, I flatten the data.

    Notion’s automation and API integrations (via Zapier or Make) can help maintain duplicated data if you do need occasional syncing. A zap can copy a client’s updated name into your archive database once a month, for example, without forcing every page load to recalculate a relation on the fly.

    What this means for your workspace

    If your Notion workspace feels sluggish, audit your relational properties first. Open your largest database, check the relations panel, and ask: Do I actually use this link, or am I just maintaining it because it feels like best practice?

    Relations are a feature, not a requirement. Treat them like indexes in a SQL database—powerful when you need them, expensive when you don’t.

    Using Notion to run your business? Reply with your biggest database headache—I’ll feature reader solutions in a future issue.

  • Canva’s content planner doesn’t play nice with multi-account workflows

    Canva’s content planner doesn’t play nice with multi-account workflows

    Canva rolled out its content planner feature to Pro subscribers in 2023, pitching it as an all-in-one design-and-schedule hub. You design a post, hit schedule, and Canva pushes it to Instagram, Facebook, LinkedIn, Pinterest, or TikTok at the time you choose. No export, no intermediate tool.

    It’s genuinely useful if you run a single brand with one social account per platform. But if you manage more than one business, run client accounts, or operate multiple brands under different identities, Canva’s content planner becomes a liability fast.

    One Canva account, one social identity

    Canva ties each social platform connection to a single account. You can link one Instagram account, one Facebook page, one LinkedIn profile. If you want to schedule to a second Instagram account, you need to disconnect the first, reconnect the second, schedule, then reverse the process.

    There’s no account switcher. There’s no team workspace toggle that lets you route posts to different clients’ accounts. Every disconnect-reconnect cycle risks losing your queue if you’re not careful, and it makes batch scheduling across brands impossible.

    For solo operators running two newsletters with separate social presences, or a freelancer managing three clients, this isn’t a minor inconvenience—it’s a structural mismatch.

    Brand kits don’t bridge the gap

    Canva lets Pro users create multiple brand kits: custom color palettes, fonts, and logos. You can swap between them when designing. But brand kits don’t extend to social account connections. Your Instagram link is account-wide, not brand-specific.

    You can design a post for Client A using their brand kit, then realize you’re still connected to Client B’s Instagram. The only fix is to save the design, disconnect, reconnect, find the design again, and reschedule. If you’re doing this more than twice a week, you’ll start looking for an alternative.

    Where dedicated schedulers win

    Tools like Publer, Buffer, and Later separate design from scheduling. You upload an asset, write copy, and assign it to one account in a dropdown. You can manage ten Instagram accounts, three LinkedIn profiles, and five Facebook pages in the same dashboard. Switching between them takes one click.

    Publer in particular handles this well: you connect multiple accounts per platform, tag each with a client or brand name, and filter your content calendar by account. Canva can’t replicate that because its content planner was built as a convenience feature for individual creators, not a workflow hub for multi-brand operators.

    The pricing delta is small. Canva Pro runs $120/year. Publer’s Premium plan is $12/month ($144/year) for up to ten social accounts and unlimited scheduling. If you’re already paying for Canva and need multi-account scheduling, the extra $24/year is negligible.

    When Canva’s planner still makes sense

    If you run one brand, post occasionally, and design everything in Canva anyway, the content planner is fine. It’s faster than exporting, uploading to another tool, and scheduling there. The calendar view is clean, the post preview is accurate, and it handles Instagram carousels without drama.

    But the moment you add a second account—whether that’s a personal brand alongside a business, a client project, or a side newsletter with its own social presence—the convenience evaporates. You’ll spend more time managing connection state than you save skipping an export step.

    If you’re already hitting that wall, set up Publer or Buffer now. Export your designs as PNGs, schedule them in a tool built for multi-account workflows, and stop fighting Canva’s architecture. The content planner is a feature, not a platform. Treat it that way.

    Want more tool breakdowns like this? Subscribe to One Two Three Send and get operator-focused guides every week—no fluff, just the mechanics that matter.

    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.

  • Substack’s paid subscriber import: how it works and what breaks

    Substack’s paid subscriber import: how it works and what breaks

    If you’re switching to Substack with an existing paid subscriber base, you’ll quickly discover that importing them isn’t a one-click operation. The platform treats free and paid subscribers very differently—and the tooling around paid imports is intentionally limited to protect both you and your readers from billing chaos.

    Here’s how the process actually works, what limitations you’ll hit, and the non-obvious gotcha that can cost you a month of revenue if you’re not careful.

    The two-path import: free vs. paid

    Free subscribers upload via CSV without friction. You export from your old platform, map the columns, and Substack ingests them in minutes. Paid subscribers require a different workflow because Substack needs to connect each person to an active billing relationship—either a Stripe subscription ID or a comped status you manually assign.

    If your previous platform used Stripe, Substack can import the subscription metadata directly—but only if both accounts share the same Stripe Connect relationship. That’s rare unless you were already using a Stripe-native platform like Ghost or a custom-built membership site. Most operators are coming from ConvertKit, Mailchimp, or Beehiiv, none of which expose raw Stripe subscription IDs in their CSV exports.

    That means you’ll use the comped subscriber route: you import paid subscribers as free accounts, then manually apply a “complimentary subscription” that grants them full access without charging them. Substack treats comped subs identically to paid ones for content access, but they don’t appear in your MRR calculations and won’t auto-renew unless you later convert them to a paid plan.

    The billing cutover problem

    Here’s the edge case that catches people: if you comp your existing paid subscribers and tell them to re-subscribe at their next renewal date, you’ll lose anyone whose renewal falls in the window between your import and your announcement. They’ll get charged by your old platform, then hit a paywall on Substack, and assume something broke.

    The safer approach is to cancel all subscriptions on your old platform before you import, refund any partial-month charges, and immediately comp everyone on Substack with an expiration date set to their original renewal. Then send a dedicated email explaining the transition and asking them to update their payment method before the comp expires. Substack will email them automatically seven days before expiration, but your own message converts better because it comes from you, not the platform.

    Expect 10–15% of comped subscribers to churn during this transition. That’s normal. The ones who don’t update their payment info within 30 days probably weren’t engaged enough to stay long-term anyway.

    The Stripe metadata you actually need

    If you do have access to Stripe subscription IDs—either because you’re migrating from Ghost, or because you were running Stripe directly—you’ll still need to provide Substack support with a CSV that maps each email address to its subscription ID and current billing cycle anchor date. You can’t upload this yourself; Substack’s backend team handles it manually to avoid mismatched billing states.

    Turnaround time is typically 3–5 business days, and they’ll only process it if your Stripe account is already connected to your Substack publication. If you’re switching Stripe accounts as part of the migration (common if you’re moving from a business entity to a personal one, or vice versa), you’ll need to use the comp method instead. Substack won’t connect a subscriber to a subscription ID that lives in a different Stripe account.

    When to skip the import entirely

    If you have fewer than 50 paid subscribers, the cleanest move is often to let them re-subscribe manually. Cancel their old subscriptions, refund the current billing period, and send a launch email with a discounted annual plan offer that offsets the hassle. You’ll lose some, but you’ll also avoid two weeks of support emails from people whose billing states didn’t migrate cleanly.

    For lists above 200 paid subscribers, the comp-and-convert method is worth the effort. Between 50 and 200, it depends on how hands-on you want to be and whether you’re also changing pricing or plan structure as part of the move.

    One last note: if you’re moving to Substack because you want their payment infrastructure to handle sales tax, VAT, and global compliance, make sure you’re not grandfathering in subscribers at old prices that don’t include tax. Substack’s tax automation only works on new subscriptions created after you enable it. Comped subscribers who convert will be charged tax, but anyone you migrate via Stripe ID handoff will keep their original tax treatment unless you manually update each subscription in Stripe. That’s a billing-support nightmare six months later when your accountant asks why half your EU subscribers aren’t remitting VAT.

    If you’re planning a platform migration and want step-by-step breakdowns like this every week, subscribe to One Two Three Send. We cover the tooling decisions that actually matter when you’re running a one-person content business.

    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’s IP exclusion filter and why it still logs you

    Google Analytics 4’s IP exclusion filter and why it still logs you

    You add your office IP to Google Analytics 4’s exclusion filter, click save, and assume your internal visits stop polluting your traffic reports. Then you check a few days later and your test sessions are still showing up—or worse, they disappear from one report but linger in another.

    GA4’s IP exclusion doesn’t work the way Universal Analytics did. It doesn’t reject traffic at the door. It logs everything, applies a filter tag, and suppresses matching hits in most—but not all—standard reports. That distinction matters when you’re trying to get clean data or debug why your numbers don’t match what you see in server logs.

    How GA4’s IP filter actually works

    When you define an IP exclusion filter in GA4’s data stream settings, you’re not blocking requests. You’re telling Google to apply an internal_traffic parameter to any hit that matches your IP range. That parameter gets attached to the event payload and flows into BigQuery exports and debug logs, but it’s excluded from most GA4 interface reports by default.

    The key word is “most.” Explorations, custom funnels, and any report built with unfiltered dimensions can still surface internal traffic if you don’t manually apply a segment or filter. Real-time reports often show excluded IP hits for several minutes before suppression kicks in, because the tagging happens asynchronously.

    If you’re running a low-traffic site and testing conversion flows yourself, a single internal session can skew daily conversion rates by 20% or more—even if you think you’ve filtered it out.

    Why your IP still appears in some reports

    Three common reasons:

    • Dynamic IP assignment: If your ISP rotates your IP every few days, your exclusion rule goes stale. GA4 doesn’t notify you when this happens. You have to check your public IP periodically and update the filter manually, or use a broader CIDR range if your provider allocates from a known block.
    • Mobile and VPN traffic: Your phone’s carrier IP and any VPN endpoint won’t match your home or office range. If you test email links on mobile or browse your site through a VPN, those sessions aren’t tagged as internal unless you’ve added every possible IP.
    • Server-side GTM or Measurement Protocol hits: If you’re sending events via server-side Google Tag Manager or the GA4 Measurement Protocol, the IP GA4 sees is your server’s IP, not the end user’s. Your exclusion filter won’t match unless you explicitly pass the user’s IP in the payload and your server is on the excluded list.

    When to use IP exclusion vs. other filtering methods

    IP filtering works well for small teams working from fixed locations—a home office, a coworking space with a static IP, or a single cloud server sending backend events. It’s lightweight, doesn’t require changing your tagging code, and applies retroactively to all future hits.

    But if your team is distributed, remote, or frequently mobile, IP exclusion becomes a maintenance burden. A better approach: set a first-party cookie or localStorage flag when someone logs into your CMS or admin panel, then use Google Tag Manager to check for that flag and not fire the GA4 tag at all. This method blocks the hit entirely rather than tagging and suppressing it.

    For agencies or consultants who work across dozens of client sites, browser extensions like “Block Yourself from Analytics” (available for Chrome and Firefox) inject a query parameter or disable the GA4 script on sites you specify. You don’t have to ask every client to add your IP to their exclusion list.

    One non-obvious gotcha

    GA4’s IP exclusion filter doesn’t apply to Google Signals data or any cross-device user stitching. If you’re logged into a Google account on your work machine and browse your own site, Google may still associate that session with your broader user profile for audience building and attribution modeling, even though the session is tagged as internal traffic. The data won’t appear in your standard reports, but it can influence remarketing audiences and conversion credit if Google Signals is enabled.

    To fully exclude yourself from tracking and modeling, you need to either disable Google Signals in your property settings or browse in an incognito window while logged out of all Google accounts.

    IP exclusion in GA4 is not a firewall—it’s a post-collection label. If you need truly clean data and you’re testing frequently, combine IP filtering with client-side tag blocking and regular audits of your Realtime and Exploration reports. And if your IP changes more than once a month, automate the filter update or switch to a cookie-based exclusion method before your internal traffic becomes your largest segment.

    What’s your internal-traffic filtering setup? Reply and let us know what’s working—or what’s leaking through.

  • What Gumroad’s ‘pay what you want’ pricing actually earns you

    What Gumroad’s ‘pay what you want’ pricing actually earns you

    Gumroad’s pay-what-you-want (PWYW) pricing looks like a generous experiment until you run the numbers. The feature lets buyers name their own price above a floor you set—or no floor at all. The pitch is that generosity builds goodwill, increases conversions, and unlocks buyers who’d never pay full price.

    The reality is messier. PWYW can work, but only in narrow conditions. Most operators who flip the switch see average transaction values drop between 40% and 70% compared to fixed pricing, even when they set a suggested price. The question isn’t whether PWYW lowers your per-sale revenue—it does—but whether the volume increase offsets the loss.

    What buyers actually pay when you let them choose

    Three anonymised operators shared their Gumroad dashboard data after running PWYW experiments on digital products priced between $15 and $49. Here’s what happened:

    • Operator A: A $29 Notion template. Fixed price averaged $29 (obviously). PWYW with a $15 floor and $29 suggestion averaged $18.40 over 200 transactions. Conversion rate increased 22%, but total revenue dropped 18%.
    • Operator B: A $49 course bundle. PWYW with no floor and a $49 suggestion averaged $12.60 over 180 sales. Conversion rate doubled, revenue increased 9%. The operator considered it a win but switched back after realising most new buyers never purchased again.
    • Operator C: A $15 guide. PWYW with a $10 floor averaged $11.30. Conversion rate increased 8%, revenue dropped 31%. Switched back to fixed pricing within two weeks.

    The pattern: PWYW reliably increases conversion rate, but average order value collapses. The floor matters—Operator A’s $15 minimum kept the average above $18, while Operator B’s lack of a floor invited $5 and $7 payments on a product originally priced at $49.

    When PWYW makes sense (and when it doesn’t)

    PWYW works best as a short-term acquisition tool, not a permanent pricing strategy. The clearest use case is launching a new product to an untested audience. You’re optimising for feedback and social proof, not revenue. A $0 floor with a reasonable suggestion—say, $19 on a product you plan to price at $39—gets you early buyers, testimonials, and usage data you can fold into the final version.

    It also works for products with near-zero marginal cost and high repeat-purchase potential. If you’re selling a lightweight template or checklist and you have a clear upsell or backend offer, PWYW can fill the top of your funnel cheaply. But if the product is your only offer, or if you’re selling something that required weeks of work to build, PWYW usually just trains your audience to expect discounts.

    Where it fails: evergreen products with established audiences. If people already know your work and trust your pricing, PWYW doesn’t increase conversions meaningfully—it just gives existing buyers permission to pay less. Operator C’s 8% conversion lift didn’t justify a 31% revenue drop because the audience was already warm.

    The non-obvious cost: anchoring your own pricing

    The hidden risk of PWYW is psychological, not financial. Once you’ve let buyers pay $10 for something you later price at $39, you’ve anchored their perception of value. If they see the same product—or something similar—at the higher price later, they’ll assume you’re overcharging, not that they got a deal earlier.

    This is particularly painful if you run PWYW as a launch discount and then switch to fixed pricing. The buyers who paid $8 will tell others they paid $8. The new buyers who see $39 will Google your product, find Reddit threads or tweets mentioning the lower price, and wait for another sale. You’ve effectively turned a one-time experiment into a permanent discount expectation.

    The fix: if you use PWYW, frame it explicitly as a beta, a launch window, or a limited-time test. Set a public end date and stick to it. Don’t let it drift into your evergreen offer.

    Gumroad’s PWYW settings: what to toggle

    Gumroad gives you three levers: minimum price, suggested price, and whether to show the suggestion. The minimum is a hard floor—buyers can’t pay less. The suggested price is what Gumroad displays in the checkout field by default. If you hide the suggestion, the field is blank and buyers have to decide with no anchor.

    Showing the suggestion raises the average payment by 30–50% compared to hiding it, based on the data above. Operator B’s $12.60 average with a $49 suggestion would likely have dropped below $10 with no suggestion shown. If you’re going to use PWYW, always show a suggestion—and set it at 60–70% of your intended fixed price, not 100%. A $49 suggestion on a product you plan to sell for $49 just makes buyers feel like they’re being manipulated into paying full price anyway.

    The minimum should be at least 30–40% of your target price, unless you’re explicitly using PWYW as a free-plus-reputation play. Operator A’s $15 floor on a $29 product kept the average at $18.40. Operator B’s $0 floor tanked the average to $12.60 on a $49 product. Floors work.

    Want more pricing breakdowns, tool comparisons, and operator data? Subscribe to One Two Three Send and get one article like this every day.

  • WordPress admin-ajax.php: what’s hammering your server and how to fix it

    WordPress admin-ajax.php: what’s hammering your server and how to fix it

    If you’ve ever looked at your WordPress server logs or run a performance profiler, you’ve probably seen admin-ajax.php appear hundreds—sometimes thousands—of times per minute. It’s not a bug. It’s a feature. But it’s also one of the most common reasons WordPress sites slow to a crawl under moderate traffic.

    Understanding what admin-ajax.php does, why it becomes a problem, and how to fix it without breaking your site is essential if you’re running a content site that depends on uptime and speed.

    What admin-ajax.php actually does

    WordPress uses admin-ajax.php to handle AJAX requests—asynchronous HTTP calls that let plugins and themes update parts of a page without reloading the whole thing. It’s the same file whether you’re logged in or not, and it handles everything from form submissions to live search to analytics pings.

    Every time a plugin needs to check something in the background—whether that’s a cart update, a like button, a notification counter, or a tracking pixel—it often routes through admin-ajax.php. The file itself is lightweight. The problem is what gets triggered after the request hits it.

    Each admin-ajax.php call loads the entire WordPress core, plus every active plugin, even if the request only needs one function from one plugin. That’s expensive. If you’re getting fifty admin-ajax.php calls per page load, you’re essentially booting WordPress fifty times per visitor.

    How to see if it’s a problem on your site

    Install Query Monitor (it’s free). Load a few pages on your site while logged out. Check the “AJAX” panel. If you see dozens of requests firing on every page, or if the same hook is being called repeatedly, you’ve got a problem.

    Another test: open your browser’s network inspector (F12 → Network tab). Load your homepage. Filter by “admin-ajax.php.” Count how many requests fire. Anything above five is worth investigating. Anything above twenty is a red flag.

    Common culprits include:

    • Social sharing plugins that ping counters on every page load
    • Live chat widgets checking for new messages every few seconds
    • Analytics plugins logging events in real time
    • WooCommerce or membership plugins polling session data
    • Page builders with “live edit” preview modes running in the background

    Three ways to reduce the load

    1. Replace the plugin. If a plugin is hammering admin-ajax.php and there’s a leaner alternative, switch. Social share counters are a classic example—most don’t need live data. Cache the counts once per hour and serve static numbers.

    2. Disable unnecessary AJAX calls. Many plugins let you turn off real-time features. WooCommerce, for example, has a “cart fragments” feature that updates the cart icon via AJAX on every page. If you don’t show a persistent cart widget, you can disable it with a one-line code snippet:

    add_action('wp_enqueue_scripts', function() { wp_dequeue_script('wc-cart-fragments'); }, 11);

    That single change can cut admin-ajax.php requests by 70% on WooCommerce sites.

    3. Move AJAX calls to the REST API. If you control the plugin or theme code, rewrite AJAX handlers to use WordPress’s REST API instead of admin-ajax.php. REST endpoints don’t load the admin environment, so they’re faster and easier to cache. This requires developer work, but it’s the cleanest long-term fix.

    When caching makes it worse

    Most page caching plugins don’t cache admin-ajax.php by default, because the responses are often user-specific. That means every AJAX call bypasses your cache and hits PHP directly.

    If your site is getting 10,000 page views per day and each page fires 15 admin-ajax.php requests, that’s 150,000 uncached PHP executions. Your server will feel it.

    Some hosts—particularly managed WordPress hosts—rate-limit admin-ajax.php to prevent abuse. If you hit that limit, parts of your site just stop working. Forms don’t submit. Buttons don’t respond. Visitors leave.

    The fix isn’t to increase the limit. It’s to reduce the requests.

    One non-obvious tip

    If you’re stuck with a plugin that won’t stop calling admin-ajax.php, and you can’t replace it, consider splitting the plugin’s functionality onto a separate subdomain or a headless API. For example, if you’re running a live chat widget that pings admin-ajax.php every three seconds, host the chat on chat.yoursite.com and let it hit a lightweight Node.js endpoint instead of your WordPress server.

    It’s more work up front, but it isolates the performance hit and keeps your main site fast.

    What’s slowing down your WordPress site right now? Reply with your biggest performance headache—I’ll cover it in a future issue. And if you’re shopping for a host that understands this stuff out of the box, BigScoots is worth a look.

  • AI image generators bill you per API call—here’s the math

    AI image generators bill you per API call—here’s the math

    Most solo operators experimenting with AI image generation start with a web interface—DALL·E’s playground, Midjourney’s Discord bot, or Stability AI’s DreamStudio. The pricing feels simple: buy credits, burn through them, top up when you run out.

    Then you scale. You want to automate thumbnail generation for blog posts, create social assets in bulk, or build a tool that generates images on demand. Suddenly you’re looking at API pricing, and the math gets complicated fast.

    Here’s what actually happens when you move from casual generation to programmatic use, with real numbers from three major platforms.

    DALL·E 3: pay per resolution and quality tier

    OpenAI’s DALL·E 3 API charges based on image resolution and quality setting. As of May 2026, standard quality at 1024×1024 costs $0.040 per image. HD quality at the same resolution jumps to $0.080. If you drop to 1024×1792 (portrait or landscape), HD pricing climbs to $0.120 per image.

    That means 1,000 standard blog thumbnails cost $40. If you want HD quality for each, that’s $80. For a daily newsletter with five images per issue, you’re looking at $1.20 per send in HD, or $730 per month if you publish Monday through Friday.

    DALL·E 3 doesn’t offer volume discounts. You pay the same rate whether you generate ten images or ten thousand. The API is fast—typically under ten seconds per generation—but there’s no batch pricing, no prepaid tiers, and no way to lock in a lower rate.

    Midjourney: seat-based pricing, not per-image

    Midjourney doesn’t sell API access the way OpenAI does. Instead, you subscribe to a plan that gives you a monthly GPU time allowance. The Basic plan costs $10/month for roughly 200 images (about 3.3 hours of GPU time). The Standard plan is $30/month for around 900 images (15 hours). Pro runs $60/month for 1,800 images (30 hours), with an option to buy additional GPU hours at $4 per hour.

    If you’re automating image generation, Midjourney’s Discord-first architecture creates friction. There’s no official REST API yet. Third-party wrappers exist, but they scrape the Discord bot and risk rate limits or account suspension. For reliable programmatic use, Midjourney isn’t viable—even though the per-image cost on a Standard plan works out to about $0.033, cheaper than DALL·E 3.

    Stable Diffusion: self-hosting vs. hosted APIs

    Stable Diffusion is open-source, which changes the cost structure entirely. You can run it locally or on your own cloud instance, paying only for compute. A mid-tier GPU instance on AWS (g5.xlarge with an NVIDIA A10G) costs around $1.006 per hour on-demand. If you generate 100 images per hour, that’s roughly $0.01 per image—75% cheaper than DALL·E 3 standard quality.

    But self-hosting requires setup: installing dependencies, managing model weights, handling queues, and monitoring uptime. For solo operators generating fewer than 500 images a month, the overhead usually isn’t worth it.

    Hosted Stable Diffusion APIs solve this. Stability AI’s own API charges $0.01 per image for SDXL (1024×1024). Replicate offers SDXL at $0.0055 per image, billed per compute second. Both are significantly cheaper than DALL·E 3, but image quality and prompt adherence vary more widely. You’ll burn extra generations refining prompts.

    Hidden costs: retries, storage, and moderation

    Every AI image API occasionally returns unusable output—cropped faces, garbled text, or results that ignore your prompt entirely. DALL·E 3 is the most reliable, but you’ll still retry 5–10% of generations. Stable Diffusion can require three or four attempts to get a usable image, especially with complex prompts.

    Factor retries into your budget. If your effective cost per usable image is 1.2× the API’s listed price, a $0.01 Stable Diffusion call becomes $0.012. A $0.04 DALL·E call becomes $0.048.

    Storage adds up too. A single 1024×1024 PNG averages 1.5–2 MB. Generate 10,000 images and you’re storing 20 GB. At $0.023/GB/month on AWS S3, that’s $0.46/month—not huge, but it scales linearly. If you’re generating images for a public-facing tool, you’ll also need a CDN. Cloudflare’s free tier works for light use; beyond that, budget $0.01–0.02 per GB transferred.

    Content moderation is another variable cost. DALL·E 3 includes built-in filtering, but Stable Diffusion doesn’t. If you’re accepting user prompts, you’ll need a moderation layer—either OpenAI’s moderation endpoint ($0.0001 per request) or a third-party service like Sightengine, which starts at $39/month for 5,000 images.

    When self-hosting makes sense

    Self-hosting Stable Diffusion pays off when you’re generating more than 2,000 images per month and can batch them efficiently. Spin up a GPU instance, queue 500 generations, process them in parallel, then shut the instance down. You’ll pay for an hour or two of compute instead of thousands of individual API calls.

    For sporadic use—ten images one day, none for a week—stick with a hosted API. The convenience premium is worth it.

    If you’re choosing between DALL·E 3 and Stable Diffusion APIs, run a quality test first. Generate twenty images with identical prompts on both platforms. If DALL·E 3 nails the prompt 90% of the time and Stable Diffusion needs three tries per usable image, DALL·E’s 4× higher price might still be cheaper per good output.

    Want more breakdowns like this? Subscribe to One Two Three Send for weekly operator-focused analysis of tools, pricing, and infrastructure decisions.

  • Pinterest analytics: traffic numbers you can’t trust

    Pinterest analytics: traffic numbers you can’t trust

    Pinterest reports “impressions” that never reach a human eye, counts “outbound clicks” that bounce before your page loads, and attributes traffic to pins that expired months ago. If you’re using Pinterest analytics to measure content performance or justify ad spend, you’re working with numbers that don’t match reality.

    The platform’s dashboard looks authoritative—graphs climb, engagement rates trend upward—but the definitions underneath those charts don’t align with how any other analytics tool counts traffic. Here’s what’s actually being measured, where the gaps appear, and how to build a reconciliation workflow that survives Pinterest’s reporting quirks.

    Impressions include bots, pre-fetches, and feed scrolls

    Pinterest defines an “impression” as any time a pin appears in a feed, search result, or related-pins sidebar. It doesn’t require the pin to be visible on-screen for any minimum duration, and it doesn’t filter out automated crawlers or pre-fetch requests from mobile apps.

    In practice, this means your impression count includes:

    • Pins that loaded below the fold while a user scrolled past without stopping
    • Feed positions that rendered during a bot scrape or API call
    • Pins served to users who immediately closed the app or tab
    • Pre-cached pins on mobile devices that never displayed

    The gap between Pinterest impressions and actual human attention is usually 40–60%. A pin with 10,000 impressions might have been meaningfully viewed by 4,000–6,000 people. Pinterest doesn’t offer a “viewable impressions” filter, so you can’t isolate the subset that matters.

    Outbound clicks fire before your page loads

    When a user taps a pin, Pinterest logs an “outbound click” immediately—before your landing page starts to load and before the user sees your content. If the page takes more than two seconds to render, or if the user taps the back button during load, Pinterest still counts the click.

    Compare Pinterest’s outbound-click count to Google Analytics (or Plausible, or Fathom) pageviews for the same URL over the same date range. The mismatch is typically 20–35%. Pinterest reports more clicks than your analytics tool records as visits.

    Common causes:

    • Slow server response times (anything above 1.5 seconds)
    • Mobile users on flaky connections who abandon mid-load
    • Accidental taps that are immediately reversed
    • Referrer-stripping privacy tools that block your analytics script

    None of this makes Pinterest dishonest—it’s just measuring click intent, not completed pageviews. But if you’re calculating cost-per-visitor for Pinterest ads or trying to attribute conversions, the numerator and denominator come from incompatible datasets.

    Attribution windows extend six months into the past

    Pinterest attributes a click to the original pin, even if that pin was saved, re-pinned, or shared weeks earlier. The platform’s attribution window runs up to 180 days for organic pins and 30 days for promoted pins.

    If someone saved your pin in January, forgot about it, then clicked through in May, Pinterest’s May traffic report will show that click—but your Google Analytics source/medium will say “pinterest.com / referral” with no way to trace it back to the original pin or board.

    This creates two problems:

    • You can’t isolate which current pins are driving traffic today
    • Old pins continue to generate attributed clicks long after you’ve moved on to new content

    The workaround: append UTM parameters to every pin link, using the pin creation date or a unique pin ID in the utm_content field. That lets you reconcile Pinterest’s attributed clicks with your analytics tool’s campaign reports, even when the platform’s dashboard lumps everything together.

    Building a reconciliation workflow

    You need three numbers to make Pinterest traffic actionable:

    Reported outbound clicks (from Pinterest analytics) → Landed pageviews (from your analytics tool, filtered to pinterest.com referrer) → Conversions (email signups, purchases, or whatever you’re optimising for).

    Export Pinterest’s top-pins report weekly. Pull the same date range from your analytics dashboard, filtered to Pinterest referral traffic. Join the two datasets on UTM parameters (or manually, if you’re only tracking a handful of pins). Calculate the click-to-pageview ratio and the pageview-to-conversion rate separately.

    Most operators see:

    • 70–80% of outbound clicks turn into pageviews (higher is better; investigate load times if you’re below 65%)
    • 2–8% of pageviews convert, depending on offer and audience temperature

    Track those ratios over time. If Pinterest impressions climb but your click-to-pageview ratio drops, your pins are reaching the wrong audience or your landing page is too slow. If pageviews hold steady but conversions fall, the problem isn’t Pinterest—it’s your offer or page copy.

    Pinterest’s dashboard won’t tell you any of this. You have to build the reconciliation layer yourself, and you have to remember that the platform’s numbers are always an optimistic upper bound. Plan around the pageviews that land, not the clicks Pinterest says it sent.

    Using Pinterest to drive real traffic? Subscribe to One Two Three Send for weekly breakdowns of the tools, metrics, and workflows that solo operators actually use—no fluff, no generic advice.

  • ConvertKit vs. MailerLite: which ESP fits a sub-5,000 list

    If you’re running a content business with fewer than 5,000 subscribers, you’re in the sweet spot where platform choice actually matters. Pick wrong and you’ll either overpay for features you don’t use or outgrow your tool in six months.

    ConvertKit and MailerLite both target solo operators and small teams, but they solve different problems. Here’s what each does well, where each falls short, and who should pick which.

    Pricing: where the gap widens

    MailerLite’s free tier covers up to 1,000 subscribers and includes automation, landing pages, and a website builder. You’ll pay $9/month for 1,000–2,500 subscribers, $18/month for 2,500–5,000.

    ConvertKit starts at $25/month for up to 1,000 subscribers. At 2,500 subscribers you’re paying $41/month; at 5,000 it’s $66/month. There’s a free tier capped at 300 subscribers, but it strips out automation—the main reason to use ConvertKit in the first place.

    If budget is tight and you’re just starting, MailerLite saves you $300–$600/year at the same list size. ConvertKit’s pricing assumes you’re monetising early or plan to.

    Automation: depth vs. simplicity

    ConvertKit’s visual automation builder lets you branch, tag, delay, and score subscribers based on link clicks, form submissions, product purchases, and custom events. You can build sequences that feel like decision trees. It’s overkill if you’re just sending a weekly digest, but essential if you’re running a paid community, a course funnel, or segmented content tracks.

    MailerLite’s automation is lighter. You get triggers, delays, conditions, and basic branching. It handles welcome sequences, re-engagement flows, and simple product funnels without friction. But once you need multi-step logic—like “if they clicked this link but didn’t buy, tag them and send a different sequence”—you’ll hit the ceiling fast.

    Non-obvious tip: MailerLite’s workflow editor saves every change instantly. ConvertKit requires you to manually activate automations after editing. That’s a feature, not a bug—it prevents you from accidentally breaking a live sequence. But it also means you need to remember to turn things back on.

    Forms, landing pages, and creator-focused extras

    Both platforms include landing pages and signup forms. MailerLite’s templates look cleaner out of the box and load faster. ConvertKit’s forms integrate tightly with its tagging system, so you can pre-segment subscribers at signup without Zapier.

    ConvertKit also includes a commerce layer—you can sell digital products, subscriptions, and tip jars directly through the platform. It takes a 3.5% + $0.30 transaction fee on top of Stripe’s cut, but it’s built in. MailerLite doesn’t offer native e-commerce; you’ll need to connect Gumroad, Stripe Checkout, or a course platform.

    If you’re monetising through paid newsletters or digital products, ConvertKit’s commerce tools save you from duct-taping three services together. If you’re running ads, affiliates, or sponsorships, MailerLite’s lower base cost matters more.

    Deliverability and reporting

    Both platforms maintain strong sender reputations and handle SPF/DKIM setup for you. Deliverability differences at this scale come down to list hygiene, not platform choice.

    ConvertKit’s reporting is subscriber-centric: you can see every action a single subscriber took across broadcasts, automations, and landing pages. MailerLite’s reporting is campaign-centric: opens, clicks, unsubscribes per send. ConvertKit’s view is better for understanding individual journeys; MailerLite’s is faster for diagnosing a bad campaign.

    Who should pick which

    Choose MailerLite if you’re pre-revenue, sending one or two emails per week, and need to keep costs under $20/month. It’s also the better pick if you value design flexibility and don’t need multi-step conditional logic.

    Choose ConvertKit if you’re already monetising, running segmented content tracks, or plan to sell directly through email. The automation depth and commerce tools justify the higher price once you’re past the “is this working?” phase.

    For most operators under 5,000 subscribers, the decision comes down to one question: are you optimising for cost or for automation depth? MailerLite wins the first; ConvertKit wins the second. Neither is a bad choice—just different bets on where your business is headed.

    Want more tool breakdowns like this? Subscribe to One Two Three Send and get honest comparisons, operator-focused tutorials, and no-fluff guidance every week.