Skip to content
imessageapi

A/B testing text messages when your list is small

Most testing advice assumes a hundred thousand recipients. With four hundred customers the maths is different, and running the wrong test is worse than running none.

7 min readUpdated August 23, 2026Attribution

A small business splitting 400 customers into two groups of 200 will see a difference between them. That difference is almost always noise. Understanding when a result is real is the difference between improving your messaging and randomly changing it every month.

Test big differences, not wording tweaks

With a small list you can only detect large effects. A 2% improvement from changing 'Hi' to 'Hello' is undetectable and probably does not exist. A change from 'click here to confirm' to 'reply C to confirm' can move response by a third, and that you can see.

Not worth testing at this size

  • Greeting wording
  • Emoji or no emoji
  • Sending at 10am vs 11am
  • Minor punctuation

Worth testing

  • Reply vs click as the action
  • Named person vs business name
  • With an offer vs without
  • Day before vs same day

Split deterministically

Hash the customer ID with the test name so a given person always lands in the same arm. Random assignment per send means someone gets variant A on Monday and B on Thursday, which measures nothing.

split.ts
import { createHash } from "node:crypto";
 
export function variantFor(customerId: string, testName: string) {
const hash = createHash("sha256")
.update(`${testName}:${customerId}`)
.digest();
 
return hash[0] % 2 === 0 ? "a" : "b";
}
 
// Record it in utm_content so the arm follows the click all the way
// through to the conversion.
const link = tagged(url, {
campaign: "appointment_reminder",
content: `reply_vs_click_${variantFor(customer.id, "reply_vs_click")}`,
});

Decide the sample size before you start

Not after you look at the numbers. A rough rule for a small list: you need roughly a few hundred per arm to reliably detect a change of ten percentage points on a rate around 50%. Smaller effects need far more. If you cannot reach that, accumulate across several sends of the same campaign instead of calling it after one.

Do not peek and stop early

Checking daily and stopping when the numbers look good is the most common way small tests produce false results. Every peek is another chance for noise to look like signal. Set the end condition up front and hold to it.

Measure the outcome, not the click

A variant that gets more clicks and fewer bookings has lost. Always evaluate against the action that pays you — confirmed appointment, invoice paid, order placed — with the variant carried through in utm_content. Tracking it end to end.

Watch the metric nobody tracks

Opt-out rate per variant. A message that converts slightly better while generating twice the unsubscribes is destroying an asset to win a quarter. Track it alongside the win, and treat a rising rate as a failed test regardless of the conversion number.

The alternative to testing is a holdout

If your list is genuinely too small to test variants, do not test variants. Run a holdout instead and measure whether the campaign works at all — a far more valuable question, and one a small list can answer. How.

Next step

Generate a tagged link for whatever you send next with the UTM builder, see what this looks like in your industry, or compare the services that can send it on the providers page.