Author: onetwothreeadmin

  • Course platform file upload limits and what happens at the boundary

    Course platform file upload limits and what happens at the boundary

    Course platform file upload limits and what happens at the boundary
    Photo: DS Pugh (CC BY-SA 2.0, via Wikimedia Commons)

    If you’ve ever uploaded a 2.1 GB course video to a platform with a 2 GB file limit, you know the frustration: some platforms reject it instantly, some let it upload for 45 minutes before failing, and some accept it but never process it.

    The boundary behavior—what happens when you hit or exceed a platform’s stated limit—varies wildly across course hosting tools. And because most operators don’t test edge cases until launch week, these differences cost time, bandwidth, and occasionally subscriber trust.

    Here’s what actually happens when you push the limits on three major platforms, and how to plan around their quirks.

    Teachable: hard stop at upload start

    Teachable enforces a 3 GB per-file limit for video uploads on all plans. If your file is 3.01 GB, the upload dialog won’t start. You’ll see an error message immediately: “File exceeds maximum size.”

    This is the cleanest failure mode. You know right away, before burning bandwidth or time. The downside: Teachable doesn’t compress or transcode client-side, so if your raw export is 3.2 GB, you need to re-encode it before upload. There’s no “let the platform handle it” option.

    Workaround: use Handbrake or similar to target H.264 at a slightly lower bitrate. For most 1080p talking-head content, 4 Mbps video gets you under 2.5 GB for a 90-minute lesson without visible quality loss.

    Kajabi: accepts upload, fails silently during processing

    Kajabi’s stated limit is 5 GB per file, but the real ceiling depends on your plan and whether you’re uploading via browser or the bulk uploader. On the Basic plan, files over 4 GB often upload successfully—progress bar completes—but then sit in “Processing” indefinitely.

    No error email. No dashboard alert. The file just never becomes available to students. If you don’t manually check back 12 hours later, you won’t know it failed.

    This is the worst failure mode for operators. You’ve burned upload time, you think the content is live, and students see a blank lesson or a spinner.

    Workaround: keep files under 3.5 GB even if your plan technically allows 5 GB. And always check the “Processed” timestamp in the library view before publishing a course.

    Thinkific: queues large files, then downgrades quality

    Thinkific’s limit is officially 5 GB, but files over 2 GB enter a slower processing queue. Upload completes normally, but transcoding can take 6–24 hours depending on platform load. During that window, students see a “Video is processing” message.

    Once processed, Thinkific applies adaptive bitrate streaming. But if your source file is large and high-bitrate, the platform may serve a lower-quality version to students on slower connections—even if you uploaded 1080p.

    This isn’t a failure, but it’s a surprise. Your 4K export might stream at 720p for 40% of viewers.

    Workaround: upload a clean 1080p H.264 file at 5–8 Mbps. That’s high enough for quality, low enough that Thinkific won’t aggressively downgrade. And schedule uploads at least 48 hours before launch.

    What about Vimeo or Wistia embeds?

    If you host video externally and embed it in your course platform, you bypass the platform’s file limits entirely. Vimeo Pro allows 20 GB per file; Wistia has no hard cap but recommends under 8 GB for optimal processing.

    The trade-off: you’re now managing two dashboards, two sets of analytics, and two potential points of failure. And some course platforms (Teachable included) don’t pass completion tracking reliably when you use third-party embeds. Students can watch the full video but the lesson won’t mark complete.

    This works well for operators who already have a Vimeo or Wistia account for other content, but it’s not a universal fix.

    One non-obvious tip: test with a disposable file first

    Before uploading your final course content, create a test file at exactly your platform’s stated limit plus 10%. Use a screen recording tool or export a low-content video at high bitrate to hit the target size.

    Upload it to a draft course. Wait 24 hours. Check if it processed, if quality degraded, if it triggered any backend errors.

    This takes 20 minutes and saves you from discovering boundary behavior during a launch.

    If you’re building a course business and want more operator-level breakdowns like this, subscribe to One Two Three Send—we cover the tooling details other newsletters skip.

  • Mailchimp migration exports: what gets lost in the CSV

    Mailchimp migration exports: what gets lost in the CSV

    Mailchimp migration exports: what gets lost in the CSV
    Photo: Mailchimp via Wikimedia Commons (CC BY-SA 4.0)

    If you’ve outgrown Mailchimp or decided to move to a platform with better economics, you’ll eventually hit the export button and download a CSV of your subscriber list. That file will contain email addresses, names, and maybe a few custom fields. What it won’t contain: most of the operational context that makes your list work.

    Mailchimp’s export is designed for portability, not fidelity. The platform strips out automation state, tag relationships, segment definitions, and engagement metadata that doesn’t fit neatly into a flat file. If you import that CSV into MailerLite, Beehiiv, or any other platform without documenting what’s missing, you’ll spend weeks rebuilding workflows from memory.

    Here’s what actually gets lost, and what you need to capture before you click export.

    Tags export as a single concatenated column

    Mailchimp allows unlimited tags per subscriber. When you export, all tags for a given contact collapse into one cell, separated by commas. That’s fine if you have three tags. It’s a disaster if you’ve been tagging behavior for two years.

    Most platforms expect tags as separate boolean columns (e.g., tag_buyer, tag_clicked_launch) or as a structured array. A comma-delimited string in one field rarely imports cleanly. You’ll need to split it manually or write a script.

    Worse: tag history disappears entirely. If someone was tagged “trial_user” in March and you removed it in June, the export only shows current state. That matters if your automations rely on timing—like sending a win-back email 90 days after a tag was removed.

    What to document: Export your full tag list separately (Audience → Manage contacts → Tags). Note which tags trigger automations, which are archival, and which represent states vs. actions. Screenshot your automation canvas if it’s complex.

    Segment logic doesn’t transfer

    Segments in Mailchimp are queries, not lists. A segment like “opened any email in the last 30 days AND has tag ‘premium’ AND joined before January 2026” is just a filter. When you export subscribers, you get a snapshot of who matched that query at export time—not the logic itself.

    If you’ve built segments for behavior-based targeting (e.g., engaged readers, cart abandoners, trial expirees), you’ll need to rebuild those rules manually in your new platform. Some platforms—like Beehiiv—have simpler segmentation tools. Others, like MailerLite, offer more flexibility but require you to map Mailchimp’s condition syntax to theirs.

    What to document: Go to Audience → Segments and export each segment definition as a screenshot or text file. Note the conditions, the subscriber count, and when you last used it. If a segment feeds an automation, flag that dependency.

    Automation subscriber state vanishes

    Mailchimp tracks where each subscriber sits in each automation: pending, completed, exited, paused. That state doesn’t export. If you’ve been running a five-email onboarding series and someone is on email three, your new platform has no idea. They’ll either get nothing or restart from email one.

    This is especially painful for evergreen sequences tied to signup date or product purchase. You can’t reconstruct who’s already received what unless you cross-reference campaign send logs—and those are buried in reporting, not in the subscriber export.

    What to document: Before migrating, go to Automations and note active workflows. For each one, export the workflow report showing how many people are in-progress. If possible, pause automations a week before migration so fewer people are mid-sequence. Consider sending a manual “reset” email post-migration to anyone who might have been interrupted.

    Custom field types sometimes downgrade

    Mailchimp supports text, number, date, dropdown, and address fields. Your export will contain the values, but not the field type. A date field becomes a string. A dropdown becomes plain text. A numeric rating becomes text unless you manually convert it.

    That matters if your new platform uses field types for segmentation or conditional content. MailerLite, for instance, lets you filter by “date is within the last 30 days”—but only if the field is recognized as a date type. If it imports as text, you lose that functionality until you re-type it and re-import.

    What to document: Go to Audience → Settings → Audience fields and merge tags. Screenshot the field list with types visible. When you import to your new platform, recreate fields with correct types before uploading the CSV. Map columns carefully during import.

    What you should do a week before migrating

    Don’t wait until export day to inventory your list. A week out, do this:

    • Pause any automations that would leave subscribers mid-sequence.
    • Export your full subscriber list, tag list, segment definitions, and custom field schema.
    • Download campaign reports for the last 90 days (opens, clicks, unsubscribes by campaign).
    • Document which integrations push data into Mailchimp (Shopify orders, Typeform signups, Stripe payments). You’ll need to reconnect those.
    • Check your sending domain’s DNS records. If you’ve been using Mailchimp’s dedicated sending domain, you’ll need to reconfigure DKIM and SPF for your new platform.

    If you’re moving to a platform like Beehiiv or MailerLite, both offer migration support—but “support” usually means they’ll import your CSV, not reconstruct your automations. The more you document upfront, the less you’ll have to rebuild from memory.

    One more thing: test with a small list first

    Before importing your full list, create a test audience in your new platform with 50–100 subscribers. Import that subset, rebuild one automation, and send a test campaign. Check that tags imported correctly, custom fields retained their types, and segments return expected counts. If something broke, fix it before migrating everyone.

    Most platforms let you delete and re-import without penalty during trial periods. Use that window.

    Want more tool migration guides? Reply with the platform you’re switching to—we’ll cover the gotchas specific to that move.

    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.

  • SEO title tags: character limits in 2026 and what gets truncated

    SEO title tags: character limits in 2026 and what gets truncated

    SEO title tags: character limits in 2026 and what gets truncated
    Photo by Lukas Müller on Unsplash

    Title tags still matter in 2026—they’re the clickable blue text in search results, the browser tab label, and the fallback headline when your content gets shared. But every platform truncates them differently, and most operators write titles blind, only discovering the cut-off after Google rewrites them or Twitter chops the last three words.

    Here’s what actually displays, where truncation happens, and how to structure titles so the important part survives everywhere.

    Character limits by platform in 2026

    Google Search displays roughly 55–60 characters on desktop, 50–55 on mobile. But it measures in pixels, not characters—specifically, around 600 pixels. That means uppercase letters, wide characters like ‘W’ and ‘M’, and em-dashes eat more space than lowercase ‘i’ or ‘l’. A 58-character title in all caps gets cut at word 6; the same count in sentence case displays fully.

    Bing allows slightly more room—around 65 characters—but rewrites titles more aggressively when it detects keyword stuffing or brand names it considers redundant.

    Social platforms are stricter. Twitter (yes, still called that in open graph parsers) cuts at 70 characters but only when the card is rendered; the meta tag itself has no hard limit. Facebook truncates around 60–65 characters in link previews. LinkedIn sits at 100 characters for article headlines but shortens page titles to roughly 60 in shares.

    Email clients display title tags in ‘view in browser’ links and when newsletters embed web content. Gmail renders about 70 characters in the browser tab, Outlook around 50.

    What gets truncated—and what vanishes entirely

    Most CMS plugins and SEO tools place the site name at the end of every title, separated by a pipe or dash. That’s fine—until truncation cuts the entire descriptive phrase and leaves only your brand. Google’s algorithm now ignores the visible title in cases where it decides the cut version is uninformative, pulling replacement text from your H1, meta description, or even anchor text pointing to the page.

    Operators lose control when the replacement text doesn’t match search intent. A title like “WordPress Object Cache Configuration | YourSite” might display as “WordPress Object Cache Configuration” on desktop but just “WordPress Object…” on mobile. Google may rewrite it to “How to Configure Object Cache in WordPress—YourSite,” pulling from your intro paragraph.

    Numbers, colons, and em-dashes create natural break points. Titles structured as “Primary Keyword: Secondary Detail” survive truncation better than run-on sentences. The colon signals to rendering engines that everything before it is the core message.

    Front-load the hook, back-load the context

    The first 40–45 characters are safe everywhere. Use them for the primary keyword and the specific angle. Save brand names, dates, and supplementary phrases for the tail.

    Compare:
    “Email deliverability tips for SaaS companies in 2026—YourSite”
    vs.
    “SaaS email deliverability: what changed in 2026 | YourSite”

    The second version survives mobile truncation with the core message intact. The first cuts to “Email deliverability tips for SaaS comp…”—losing both the year and the site name, and looking like generic advice.

    If your site name is long, drop it from title tags on inner pages. Google appends it automatically in 60% of cases anyway, pulling from your homepage title or site identity settings. You’re better off using those 15 characters for a stronger hook.

    Test truncation before you publish

    Most SEO plugins show a preview, but they assume average character width. If your titles use uncommon punctuation, all-caps brand names, or UTF-8 symbols, test in a real SERP simulator.

    Free tools like Portent’s SERP Preview and Yoast’s snippet editor render titles in Google’s actual display font (Roboto on desktop, system sans-serif on mobile). Run your title through both before committing.

    For operators publishing at volume—daily blog posts, newsletter archives, product landing pages—set a template that front-loads keywords and makes the site name optional. Most WordPress themes let you customize title structure per post type. Use %%title%% | %%sitename%% for long-form content, %%title%% for time-sensitive posts where every character counts.

    When Google rewrites your title anyway

    Even a perfectly-sized title gets rewritten if Google decides it doesn’t match the query. In 2026, title rewrites happen in roughly 60% of organic impressions—up from 50% two years ago. The algorithm pulls from your H1, meta description, or visible page content when it believes those better answer the searcher’s intent.

    You can’t prevent rewrites entirely, but you can reduce them. Match your title tag to your H1. Avoid keyword-stuffed lists or promotional language in the title. If Google rewrites consistently for a high-traffic page, check Search Console’s ‘Page experience’ report—it sometimes flags titles as ‘not descriptive’ when they’re too vague or too sales-heavy.

    Truncation isn’t a ranking factor, but a truncated title that confuses users does hurt click-through rate—and CTR is a ranking signal. Structure your titles so the most important words display everywhere, even when platforms cut the rest.

    One Two Three Send covers traffic, tools, and operations for online-business builders. Subscribe for tactics like this every week.

  • Hosting control panels: cPanel, Plesk, and custom—what you gain and lose

    Hosting control panels: cPanel, Plesk, and custom—what you gain and lose

    Hosting control panels: cPanel, Plesk, and custom—what you gain and lose
    Photo by Kevin Ache on Unsplash

    Most operators never choose their hosting control panel. It comes bundled with the plan. But the interface you use to manage domains, databases, SSL certificates, and email accounts shapes how quickly you can fix problems, migrate sites, and scale your infrastructure.

    Here’s an honest look at the three control panel architectures you’ll encounter: cPanel, Plesk, and custom dashboards built by hosts. Each has clear trade-offs for solo operators and small teams running content businesses.

    cPanel: ubiquitous, consistent, but aging

    cPanel dominates shared and reseller hosting. If you’ve ever logged into a budget host, you’ve probably seen its File Manager, phpMyAdmin shortcut, and domain management grid.

    Pros:

    • Nearly universal support—documentation, tutorials, and third-party tools assume cPanel by default
    • Direct database access via phpMyAdmin is fast; no ticket required to create or drop tables
    • Email account setup is self-service, including forwarders and autoresponders
    • Backup restoration is straightforward: upload a .tar.gz archive and cPanel extracts files, databases, and email in one pass

    Cons:

    • Licensing costs increased sharply in 2019; many budget hosts passed fees to customers or migrated away
    • Interface design hasn’t changed much since 2015—it’s functional but slow to navigate on mobile
    • SSL automation lags behind newer panels; Let’s Encrypt works, but renewal sometimes requires manual nudging
    • Resource usage graphs update every five minutes, not in real time—problematic when diagnosing a traffic spike

    Best for: Operators who need predictable workflows across multiple hosts, or who run reseller setups where clients expect a familiar interface.

    Pricing note: Hosts typically bundle cPanel into plans. Standalone licenses start around $15/month for VPS users, but you’ll rarely pay that directly unless self-managing a server.

    Plesk: Windows-friendly, modular, underappreciated

    Plesk is cPanel’s main competitor, but it’s more common on European hosts and VPS providers. It runs on both Linux and Windows Server—one reason it’s popular for operators juggling WordPress and ASP.NET projects.

    Pros:

    • Cleaner UI than cPanel; tabbed navigation and search make it faster to find settings
    • WordPress Toolkit is built-in: one-click staging, cloning, security hardening, and plugin updates from the Plesk dashboard
    • Git integration is native—deploy from a repository without SSH or third-party plugins
    • Docker container management is available in most plans; useful if you’re experimenting with headless CMSes or Node.js apps

    Cons:

    • Smaller documentation ecosystem—you’ll find fewer DigitalOcean-style tutorials and Stack Overflow threads
    • Extension marketplace is useful but inconsistent; some plugins cost extra and update irregularly
    • Email management isn’t as granular as cPanel; advanced filtering requires diving into config files
    • Backup scheduling is less flexible—you can’t easily script partial backups of specific directories

    Best for: Operators who value a modern interface and need WordPress-specific tooling baked into the host dashboard. Also a good fit if you’re running mixed environments (WordPress plus a Node API, for example).

    Pricing note: Plesk licensing is comparable to cPanel—around $10–$20/month for VPS plans, bundled into managed hosting.

    Custom dashboards: fast, opinionated, locked-in

    Premium managed WordPress hosts—Kinsta, WP Engine, Flywheel, and others—skip cPanel and Plesk entirely. They build proprietary control panels optimized for WordPress workflows.

    Pros:

    • Staging environments deploy in seconds; you don’t manually clone databases or rewrite URLs
    • SSL, CDN, and DNS configuration happen in a few clicks—no certificate chains or nameserver confusion
    • Real-time performance graphs and error logs surface issues faster than cPanel’s delayed metrics
    • Automatic plugin and core updates can be scheduled per-site, with rollback options

    Cons:

    • No direct database access in most cases—you export a SQL dump or use phpMyAdmin via a secondary link, slowing down manual fixes
    • Email hosting is often excluded; you’ll need to integrate Google Workspace, Fastmail, or a transactional service like Postmark
    • Migration away from the host is harder—no standardized backup format means exporting files, databases, and DNS separately
    • Limited flexibility for non-WordPress projects; if you need a static site or a Rails app, you’re out of luck

    Best for: Operators focused exclusively on WordPress who value speed and simplicity over control. If you never touch wp-config.php or run custom cron jobs, a custom dashboard is faster.

    Pricing note: Custom dashboards come with premium managed plans—typically $30–$100+/month per site, depending on traffic and features.

    Which one matters for your business?

    If you’re migrating between hosts frequently, learning multiple clients’ sites, or troubleshooting unfamiliar setups, cPanel’s ubiquity wins. The learning curve is shallow, and you’ll find answers fast.

    If you’re managing a portfolio of WordPress sites and want tooling that reduces manual work—staging, Git deploys, security scans—Plesk or a custom dashboard cuts hours per month.

    And if you’re running a single high-traffic WordPress site where performance and uptime matter more than flexibility, a custom dashboard from a managed host like BigScoots eliminates friction.

    The wrong choice doesn’t break your business. But the right one makes every routine task—SSL renewals, database exports, email setup—faster. And for solo operators, that’s the difference between spending an hour on infrastructure and spending that hour writing.

    What control panel are you using, and what’s the one feature you wish it had? Reply to this email—I’m cataloging the gaps between what hosts offer and what operators actually need.

  • Google Analytics 4 doesn’t trust TikTok referrals. Here’s why.

    Google Analytics 4 doesn’t trust TikTok referrals. Here’s why.

    Google Analytics 4 doesn't trust TikTok referrals. Here's why.
    Photo: Saleemkce via Wikimedia Commons (CC BY-SA 4.0)

    You post a link to TikTok. Someone clicks. They land on your site. You check Google Analytics 4 an hour later, and the visit shows up under “direct / (none)” instead of TikTok.

    This isn’t a bug. It’s a design collision between how TikTok’s in-app browser works and how GA4 attributes traffic. The result: you undercount social performance and make bad decisions about where to spend effort.

    Why TikTok referrals disappear in GA4

    When someone clicks a link inside the TikTok app, it opens in TikTok’s own in-app browser. That browser strips or obscures HTTP referrer headers inconsistently—sometimes it passes tiktok.com, sometimes it passes nothing, and occasionally it passes an intermediate redirect domain TikTok uses internally.

    GA4 relies on referrer headers to classify traffic sources. If the header is missing or unrecognized, GA4 dumps the session into “direct / (none).” Even when the referrer does come through, GA4’s default channel grouping doesn’t always recognize TikTok variants (like t.tiktok.com or regional subdomains) as social traffic.

    The problem gets worse if your audience uses iOS and you have App Tracking Transparency prompts blocking data handoff between apps. In those cases, the session starts fresh on your site with zero context about where it came from.

    What this looks like in practice

    Run a TikTok campaign driving to a landing page. You see 400 clicks in TikTok’s analytics dashboard. GA4 shows 180 sessions from “tiktok.com” and another 150 sessions filed under “direct.” The math doesn’t add up, and you can’t tell which creative or caption drove the missing traffic.

    One operator I spoke with in August saw only 42% of their TikTok link clicks appear as social referrals in GA4. The rest scattered across direct, referral (from unrecognized domains), and a handful labeled “(other).” They were about to kill TikTok entirely until they cross-checked server logs and realized the traffic was real—just misattributed.

    How to fix attribution for TikTok links

    The most reliable fix: UTM parameters. Append ?utm_source=tiktok&utm_medium=social&utm_campaign=[your_campaign_name] to every link you post on TikTok. GA4 will honor UTM tags even when referrer headers fail, and you’ll get clean source/medium data in your reports.

    Keep the parameters short. TikTok doesn’t display full URLs in bios or comments, but long query strings make links look spammy and reduce click-through in practice. Stick to source, medium, and campaign. Skip content and term unless you’re running paid TikTok ads with multiple creatives.

    If you’re using a link shortener (Bitly, Rebrandly, or a self-hosted option), add UTM parameters to the destination URL before you shorten it. That way the shortlink preserves attribution even if TikTok’s app strips the referrer during the redirect.

    One more step: check your GA4 channel grouping rules. Go to Admin → Data display → Channel groups → Default channel grouping, and confirm that tiktok.com and common variants like m.tiktok.com and vt.tiktok.com are classified under “Social.” If they’re missing, add a custom rule matching source “tiktok” with medium “social” or “referral.”

    When to care about this and when to ignore it

    If TikTok drives less than 5% of your traffic, the attribution gap won’t move the needle. Your time is better spent on channels you can measure cleanly.

    But if you’re testing TikTok as a growth lever—posting daily, experimenting with hooks, or running link-in-bio offers—misattribution will kill your ability to learn what works. You’ll see flat referral numbers, assume TikTok doesn’t convert, and bail before you find the format that clicks.

    The same issue affects Instagram, Snapchat, LinkedIn’s mobile app, and even some Reddit clients. The pattern is identical: in-app browsers that don’t play nice with referrer headers. The fix is the same every time—UTM parameters on every link you post to social platforms.

    Want more breakdowns of analytics quirks that cost you traffic insights? Subscribe to One Two Three Send and get one operator-focused article like this every day.

  • Social media scheduler bulk-upload CSV: what happens to malformed rows

    Social media scheduler bulk-upload CSV: what happens to malformed rows

    Social media scheduler bulk-upload CSV: what happens to malformed rows
    Photo by Shutter Speed on Unsplash

    If you’ve ever uploaded a hundred social posts via CSV and found ninety-three scheduled, you’ve hit the malformed-row problem. Most social media schedulers accept bulk uploads, but none handle errors the same way—and few tell you what went wrong until you notice gaps in your calendar.

    Here’s what actually happens when a row in your CSV doesn’t parse cleanly, and how to audit before you commit.

    What counts as malformed

    A row can fail for half a dozen reasons: missing required columns, date formats the parser doesn’t recognise, character-encoding issues (smart quotes from Excel are a common culprit), image URLs that 404, platform-specific constraints like Twitter’s 280-character limit, or account handles that don’t match any connected profile.

    Some schedulers validate the entire file before queuing anything. Others process row-by-row and skip failures silently. A third group queues everything, then marks individual posts as “failed” after attempting to publish.

    The difference matters. If you upload on a Friday afternoon and don’t check until Monday, silent skips mean your weekend content never went out.

    How each platform handles bad rows

    Publer validates the CSV before import and shows a preview table with warnings for rows that won’t schedule. You can fix inline or re-upload. Once you confirm, only valid rows enter the queue. If an image URL breaks between upload and publish time, the post stays queued but displays an error badge in the calendar view.

    Buffer queues everything and flags issues post-upload in a separate “Needs Attention” tab. Rows with missing dates get assigned the next available slot in your default queue. If a platform credential expires, posts pile up as drafts rather than failing silently.

    Hootsuite rejects the entire CSV if any row has a critical error (missing account, invalid date format). You fix the file and re-upload from scratch. Minor issues—like a post slightly over character count—get truncated automatically, and you only find out if you open the individual post.

    Later (primarily Instagram-focused) imports everything but marks rows with image-fetch errors as “Media Missing.” These appear in your calendar with a placeholder thumbnail. If you don’t review, they publish as text-only posts, which Instagram’s algorithm deprioritises heavily.

    Pre-flight checks that catch 90% of errors

    Before you upload, run your CSV through a plain-text editor (not Excel) and search for curly quotes, em dashes, and non-breaking spaces. Replace them with straight quotes, hyphens, and regular spaces.

    Check date columns for consistency. If one row uses 09/23/2026 and another uses 2026-09-23, most parsers will reject the inconsistent format or assume mm/dd/yyyy and schedule posts six months off.

    Validate image URLs by opening five random ones in a browser. If your images live on a staging server you’re about to take offline, or behind authentication, the scheduler won’t fetch them—and you’ll only notice when posts go live with broken thumbnails.

    Test with a ten-row sample before uploading your full calendar. Most schedulers let you delete queued posts in bulk, but recovering from a botched 200-row upload is tedious.

    When to skip CSV entirely

    If your workflow involves conditional logic—publish this post only if engagement on the previous one hit a threshold, or swap in alternative copy based on time-of-day performance—CSV uploads can’t handle it. You’re better off using each platform’s API or a workflow automation tool like Zapier that can branch based on trigger conditions.

    CSV also breaks down when you’re cross-posting with platform-specific customisations. A single row can’t gracefully handle “post this image to Instagram as a Reel, but to LinkedIn as a static image with a different headline.” You end up maintaining separate CSVs per network, which defeats the time-saving purpose.

    For one-off campaigns or evergreen content queues, though, CSV is still faster than manual entry—as long as you audit the upload immediately and check for gaps.

    Hit reply and tell us: which scheduler have you used for bulk uploads, and what error surprised you most?

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

  • Newsletter unsubscribe links: where platforms place them and why

    Newsletter unsubscribe links: where platforms place them and why

    Newsletter unsubscribe links: where platforms place them and why
    Photo: Alphabet, Inc. via Wikimedia Commons (Public domain)

    Unsubscribe links sit in the footer of every newsletter you send. But where in that footer—and how prominently—varies wildly across platforms. That placement isn’t just aesthetic. It changes deliverability, spam complaint rates, and reader behavior in ways most operators never notice until something breaks.

    Here’s how the major platforms handle it, what each approach signals to inbox providers, and when you should care enough to override the default.

    Footer vs. header: what the platforms do

    Most ESPs place the unsubscribe link in the email footer by default. Beehiiv, ConvertKit, MailerLite, and Substack all default to footer placement, typically in small gray text beneath your content and any footer copy you’ve added.

    Some operators ask about header placement—putting the unsub link at the top of the email, reasoning that transparency builds trust. Gmail’s one-click unsubscribe feature (which surfaces a prominent “Unsubscribe” button at the top of the interface) made this conversation louder in early 2024, but that feature pulls from the List-Unsubscribe header in your email’s metadata, not from visible link placement in your HTML.

    Moving your visible unsubscribe link to the email header doesn’t improve deliverability. It just makes it easier for casual readers to bail before they’ve read anything. The data from operators who’ve tested this consistently shows higher unsub rates with no measurable improvement in engagement from the readers who stay.

    How spam filters read unsubscribe placement

    Inbox providers—Gmail, Outlook, Yahoo—look for two signals: a visible unsubscribe link in the email body, and a List-Unsubscribe header with either a mailto or HTTPS endpoint. Both matter, but the header matters more.

    When the header is present and functional, Gmail and Yahoo display their own one-click unsubscribe button. If the header is missing or broken, they rely on the visible link in your email body. If that’s hard to find—buried in a wall of fine print, styled to blend with the background, or located off-screen on mobile—spam filters flag it.

    Most platforms handle the header automatically. Postmark, for example, injects a List-Unsubscribe header by default on all sends if you’ve set up suppression lists. Brevo and MailerLite do the same. If you’re self-hosting your email sends via SMTP or API, you need to add this header manually.

    The visible link’s placement matters less to filters than its presence and clarity. Filters scan for the word “unsubscribe” or “opt out” in the lower third of the email. If it’s there, in a legible font size (at least 10px), you’re fine. If you hide it in an image, use a euphemism (“manage preferences” alone doesn’t count), or require multiple clicks to complete the action, you risk spam folder placement—especially on Yahoo and Outlook.

    Reader behavior: bottom vs. really bottom

    There’s footer placement, and then there’s footer placement. Some operators bury the unsubscribe link below their mailing address, company registration details, and three lines of legal disclaimers. Others put it directly beneath the last content block, in the same font size as the rest of the email.

    The conventional wisdom says to make unsub easy but not prominent. The data backs that up. A 2025 analysis of 800+ newsletters by Inbox Collective found that emails with unsubscribe links placed within two scrolls of the main content had 12% lower spam complaint rates than emails where the link required three or more scrolls on mobile. Spam complaints—not unsubscribes—are the real deliverability killer. When readers can’t find the unsubscribe link, they hit “Report spam” instead.

    If your spam complaint rate is above 0.1%, check your footer. Open your last send on a phone. Count how many swipes it takes to reach the unsubscribe link. If it’s more than two, move it up or cut the text above it.

    When to customize your unsubscribe flow

    Most platforms give you a one-click unsubscribe: the reader clicks the link, lands on a confirmation page, and they’re out. Some operators add a preferences page instead—offering options to reduce frequency, switch to a digest, or unsubscribe from specific content types.

    This works if you have multiple send types and segments worth preserving. If you’re sending one weekly newsletter, a preferences page just adds friction. The reader who wanted out still wants out; now they’re annoyed.

    The exception: if you’re seeing high unsub rates on specific campaigns but low rates overall, a preferences step lets you isolate what’s driving exits. ConvertKit and MailerLite both support custom unsubscribe pages. Set one up, track which options readers pick, and adjust your content mix accordingly.

    If you’re running a free newsletter funded by sponsors or affiliates, you might be tempted to add a “Are you sure?” interstitial or an exit survey. Don’t. Every extra step increases the chance the reader hits “Report spam” instead of finishing the unsub flow. You can ask for feedback after they’ve unsubscribed—on the confirmation page—but not before.

    The one thing to check this week

    Send yourself a test email from your ESP. Open it on your phone. Scroll to the unsubscribe link and tap it. If the process takes more than two taps and five seconds, simplify it. Then check your spam complaint rate in your sending dashboard. If it’s above 0.08%, your unsubscribe flow is probably part of the problem.

    Want more breakdowns like this? Subscribe to One Two Three Send for weekly deep dives on the tools and tactics that power solo content businesses.

    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.

  • AI prompt versioning: track what worked before you lose it

    You spent twenty minutes tweaking a Claude prompt until it finally output clean, structured product descriptions in your brand voice. Three weeks later, you need the same output for a new batch—but the prompt is gone, buried in a chat thread you can’t find, or worse, overwritten when you tested a variation yesterday.

    Most solo operators treat AI prompts like scratch paper: disposable, immediate, and impossible to recover once the context window scrolls away. That works until you need to recreate a result and can’t remember what input produced it.

    Prompt versioning doesn’t require Git or a dedicated tool. It just requires a lightweight system that captures what worked, when it worked, and what you changed.

    Why prompts decay faster than you think

    Unlike code, prompts degrade invisibly. You tweak phrasing to fix one edge case and accidentally break another. You switch models—GPT-4 to Claude 3.5 Sonnet—and discover your carefully tuned instructions no longer parse the same way. You add a constraint to save tokens and lose the nuance that made the output useful.

    Three things kill prompt reliability:

    • Iteration without snapshots. You edit in place, so there’s no record of the last working version.
    • Model drift. Platforms update models without warning. A prompt that worked in July may produce different results in September, even with identical input.
    • Context loss. The instructions you typed made sense alongside three examples and a clarifying sentence. When you copy just the core prompt into a new session, it fails—and you can’t remember what the missing context was.

    The fix isn’t complex tooling. It’s structured capture.

    Three-field versioning for solo operators

    Every time a prompt produces output you’d want to replicate, save three fields in a plain text file, note, or spreadsheet:

    1. The full prompt text. Copy the entire instruction block, including system messages, examples, and formatting rules. Don’t paraphrase. Don’t summarise. If you used a multi-turn conversation to refine the output, concatenate the key messages into a single reproducible block.

    2. Model and date. Note which model and version you used (e.g., “Claude 3.5 Sonnet, 2026-09-22”). If the platform lets you pin a model snapshot or API version, record that too. When results change later, you’ll know whether the prompt failed or the model shifted.

    3. What it solved. Write one sentence describing the task: “Generates 3-sentence product descriptions with benefit-first hooks for SaaS tools” or “Extracts action items from meeting transcripts and outputs markdown checklist.” This is your search key when you need the prompt again in three months.

    Store these in a single file per project or category. A Google Doc works. So does a local text file, an Airtable base, or a Notion database. The structure matters more than the tool.

    When to snapshot vs. when to skip it

    Don’t version every throwaway query. Save prompts when:

    • The output is part of a repeatable workflow (e.g., weekly content briefs, monthly analytics summaries).
    • You spent more than ten minutes iterating to get it right.
    • You’ll need the same output format again, even if the input data changes.
    • The prompt includes non-obvious constraints, formatting rules, or edge-case handling that you’ll forget.

    Skip versioning for one-off research queries, exploratory brainstorming, or anything you won’t reuse. The goal is to capture workflow infrastructure, not every interaction.

    Forking prompts without breaking the original

    When you need to adapt a working prompt for a new use case, duplicate the entry before you edit. Label the fork with the date and a short differentiator: “Product descriptions — original” and “Product descriptions — technical audience, 2026-09-22.”

    This gives you a rollback path. If the new version underperforms, you haven’t lost the baseline. And six months from now, when you need “the version that worked for technical buyers,” you’ll know exactly where it is.

    Operators who version their prompts spend less time re-solving problems they’ve already fixed. The system doesn’t need to be formal—it just needs to exist before you need it.

    If prompt versioning saves you one lost afternoon this quarter, it’s worth the five minutes to set up. What’s one AI workflow you’d hate to recreate from scratch? That’s the first prompt to snapshot today.

    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.

  • Beehiiv ad network approval: what editors review and how long it takes

    Beehiiv ad network approval: what editors review and how long it takes

    Beehiiv ad network approval: what editors review and how long it takes
    Photo by Markus Winkler on Unsplash

    Beehiiv‘s Ad Network promises to connect newsletter operators with premium sponsors without the cold-outreach grind. But between clicking “Apply” and seeing your first ad impression, there’s a review process that isn’t clearly documented anywhere in the dashboard.

    If you’re planning to monetise through the network, here’s what actually happens during approval—and what slows it down.

    What the review team checks

    Beehiiv‘s Ad Network approval isn’t automated. A human editor reviews three things:

    • Subscriber count and engagement. The official threshold is 2,500 subscribers, but approval rates climb significantly above 5,000. More importantly, they check recent open rates. If your last five sends averaged below 30%, expect a rejection or a request to reapply later.
    • Content consistency. They’re looking for a defined niche and a regular publishing cadence. If your archive shows three posts in January and then nothing until August, that’s a red flag. Brands want predictable inventory.
    • Brand safety. The editor skims your last 10–15 issues for anything that might spook advertisers: excessive profanity, polarising political content, or anything that violates Beehiiv’s acceptable-use policy. This isn’t about ideology—it’s about whether a SaaS company will feel comfortable placing a banner next to your prose.

    One non-obvious detail: they also check whether you’re already running direct sponsorships. If you are, that’s actually a positive signal. It shows you understand ad placement and have an audience advertisers value.

    The actual timeline

    Beehiiv’s help docs say “up to five business days.” In practice, most approvals land within 48–72 hours. Rejections come faster—often within 24 hours.

    But here’s where it gets slow: if your application is borderline, it gets escalated to a second reviewer. That adds another three to five days. And if you’re flagged for manual subscriber verification (usually because your list grew unusually fast or your domain is very new), expect a week or more.

    If you haven’t heard back in seven business days, reply to your original application email. Don’t open a new support ticket—that resets the queue.

    What happens after approval

    Approval doesn’t mean ads start immediately. You’re added to the network’s inventory pool, and advertisers choose placements based on audience fit, niche, and available budget.

    For newsletters under 10,000 subscribers, it’s common to wait two to four weeks before your first ad runs. Larger lists (25,000+) typically see their first placement within a week.

    Once you’re live, Beehiiv’s system automatically inserts ads into your sends based on the placement settings you choose: top, middle, or bottom. You set a frequency cap (e.g., one ad per issue), and the network fills it when a match is available. If no advertiser is queued, the slot stays empty—your issue goes out ad-free.

    Revenue is CPM-based, and Beehiiv takes a 25% platform fee. Rates vary widely by niche, but most operators report $8–$15 CPM after the split. Payments are net-60, processed through Stripe.

    When to apply—and when to wait

    If you’re sitting at 2,600 subscribers with a 28% open rate and inconsistent publishing, wait. You’ll likely get rejected, and reapplying within 90 days rarely changes the outcome unless your metrics improve significantly.

    Better to hit 5,000 subscribers, lock in a weekly cadence for two months, and then apply. Your approval odds jump, and you’ll have enough volume to make the CPM model worthwhile.

    If you’re already running direct sponsorships at $300–$500 per placement, do the math before switching. The Ad Network is lower-friction, but direct deals almost always pay better for lists above 10,000 subscribers.

    Want more breakdowns like this? Subscribe to One Two Three Send for weekly deep-dives on the tools and tactics that power online businesses.

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

  • Newsletter archives don’t rank—unless you fix three indexing rules

    Newsletter archives don’t rank—unless you fix three indexing rules

    Newsletter archives don't rank—unless you fix three indexing rules
    Photo: NOIRLab via Wikimedia Commons (CC BY 4.0)

    Most newsletter operators publish every issue to their website. Some platforms do it automatically. Others use plugins or manual copy-paste workflows. The promise is simple: your archive becomes an SEO asset, pulling in search traffic long after each issue goes out.

    In practice, most newsletter archives never rank. Not because the content is bad—because the page is misconfigured in ways that tell Google not to index it, or to treat it as duplicate content, or to prioritize a different URL entirely.

    Here are the three indexing rules that break most newsletter archives, and how to fix each one.

    Canonical tags pointing to the wrong URL

    When a newsletter platform publishes an issue to your site, it often sets a canonical tag pointing back to the platform’s own hosted version. That’s intentional: the platform wants its URL to rank, not yours.

    Beehiiv does this by default. If you publish to both your Beehiiv-hosted archive and your WordPress site, the WordPress version includes a <link rel="canonical"> tag pointing to the Beehiiv URL. Google sees that, treats your site’s copy as a duplicate, and only indexes the Beehiiv version.

    If you want your domain to rank, you need to either turn off the Beehiiv-hosted version or manually strip the canonical tag from your WordPress template. Most themes let you override the <head> section in single.php or via a child theme. Remove the platform-generated canonical, or replace it with a self-referential one pointing to your own post URL.

    ConvertKit and MailerLite handle this differently: they don’t auto-publish to external sites, so the canonical issue only appears if you’re syndicating content to Medium, LinkedIn, or other republishing platforms. In those cases, make sure the republished version includes a canonical tag pointing back to your site—not the other way around.

    Robots meta tags blocking indexing

    Some WordPress themes and SEO plugins set noindex directives on specific post types or categories by default. If your newsletter archive lives in a custom post type or a dedicated category, it might be marked noindex without you realizing it.

    Check your site’s HTML source on a published archive page. Look for a <meta name="robots" content="noindex"> tag in the <head>. If it’s there, Google won’t index the page no matter how good the content is.

    The most common culprit is Yoast SEO or Rank Math, both of which let you set noindex at the category or post-type level. Go to the plugin’s settings, find the section for taxonomies or post types, and make sure your newsletter archive isn’t flagged. If you’re using a custom post type for newsletters, check the post-type settings specifically—many themes default custom types to noindex to avoid cluttering search results with non-standard content.

    If you don’t use an SEO plugin, the directive might be hardcoded in your theme. Search your theme files for wp_robots or robots and look for conditional logic that adds noindex based on post type, category, or tag.

    Duplicate content across multiple URLs

    If you publish the same issue to your newsletter archive, a blog category, and a standalone page, Google sees three identical copies and picks one to index—usually not the one you want.

    This happens most often when operators use a plugin like Mailchimp for WordPress or Newsletter Glue, which can auto-publish to both a custom post type and a standard blog post. The result: two URLs with identical content, no canonical tag to disambiguate, and Google indexing whichever it crawls first.

    The fix is to pick one URL structure and stick with it. If your newsletter archive lives at /newsletter/issue-47/, don’t also publish the same content at /blog/issue-47/ or /archive/issue-47/. If you need the content accessible in multiple places—say, for a category feed—use a canonical tag on the secondary URL pointing to the primary one.

    You can also use 301 redirects to consolidate old URLs if you’ve already published duplicates. Redirect the less-important URL to the one you want to rank, and Google will eventually drop the old one from the index.

    How to audit your archive in ten minutes

    Open Google Search Console and filter for pages that contain your newsletter archive slug—usually something like /newsletter/ or /issues/. Look at the Coverage or Pages report. If most of your archive is marked Excluded with a reason like “Duplicate without user-selected canonical” or “Alternate page with proper canonical tag,” you’ve got a canonical or duplicate-content problem.

    Next, spot-check three archive pages by viewing their HTML source. Search for rel="canonical" and name="robots". If the canonical points somewhere other than the page itself, or if noindex appears, you’ve found the issue.

    Finally, search Google for site:yourdomain.com/newsletter/ and see how many results appear. If the number is much lower than your total published issues, Google isn’t indexing most of your archive.

    Fix the three rules above, then submit your archive sitemap in Search Console and wait two weeks. Most archives see a 3–5× increase in indexed pages once the technical blocks are removed.

    Want more SEO walkthroughs like this? Subscribe to One Two Three Send—every issue goes straight to your inbox, and the archive actually ranks.

    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.