EM-114 · the gap that cost us the baseline
Yes, they are identified. 9,049 named people acted on the SMS step between 21 June and 18 August, the window where SMS capture collapsed. We have an email address for every single one of them, because reaching the SMS step required submitting the email step first.
6,367 of them still have no SMS consent today, and 5,850 of those are still reachable by email. That is the recoverable cohort, and it is a better target than the wider pool because these people demonstrably tried and the mechanism failed them.
Klaviyo API, 20 Aug 2026. Identified by joining submitted_form_step events on the
session cid, which links a view-1 SMS action back to the view-0 email submit in the same session.
28,452 events, 15,115 sessions. Every one of the 9,049 resolved to a live profile. Currency USD.
I said in the last report that the mobile abandoners were unrecoverable. That was wrong, and this is the correction.
Every submitted_form_step event carries a session cid. The same cid
appears on the view-0 email submit and the view-1 SMS action within one session. So even when the SMS step
captured no phone number, the email from the same session names the person.
That is the whole trick, and it means 100.0% of the people who acted on the SMS
step in the gap are identifiable, not just the ones who typed digits. I had assumed the empty
submitted_fields on the mobile path meant the person was lost. It only meant the number was lost.
What happened to those 9,049 people since:
| Where they are today | People | Share | Meaning |
|---|---|---|---|
Still NEVER_SUBSCRIBED | 6,367 | 70.4% | Tried, never got there, still has not |
Since became SUBSCRIBED | 2,013 | 22.2% | Got in later, by checkout or a retry |
UNSUBSCRIBED | 669 | 7.4% | Do not contact |
| Total identified | 9,049 | 100% | — |
Of the 6,367 with no consent, 517 cannot be emailed either, which leaves 5,850 genuinely contactable. The unreachable break down as:
| Why we cannot email them | People |
|---|---|
| Suppressed: UNSUBSCRIBE | 368 |
| Suppressed: HARD_BOUNCE | 73 |
| Suppressed: USER_SUPPRESSED | 40 |
| Suppressed: SPAM_COMPLAINT | 31 |
| Suppressed: INVALID_EMAIL | 2 |
| NEVER_SUBSCRIBED | 2 |
| Suppressed: UNSUBSCRIBE/USER_SUPPRESSED | 1 |
Independent corroboration. Before running this I estimated the baseline shortfall at roughly 6,000 to 6,700 lost SMS subscribers, by comparing June, July and August against May's rate of 4,437 a month. The event-level count of people who tried and still have no consent came out at 6,367. Two different methods, same answer, so the cohort is the gap rather than a slice of it.
This is the mechanic and the three sources, because it is the part that decides whether any of this is a compliance problem or a plumbing problem.
In Klaviyo a phone number is a profile attribute. Consent is a separate subscription write.
Anything that writes profile data can set phone_number and never touch consent: a Shopify order
sync, a form submit, an identify() call, a CSV import. Two different writes, and only the second
one grants permission to text anybody.
That is why this stayed invisible. Nothing malfunctioned in a way that would raise an alarm, and nothing
unlawful happened by storing the number. The proof that no consent was ever taken is in the data:
sms_method is None on 100.0% of all 39,918 profiles. Klaviyo stamps a method
(FORM, SHOPIFY, TEXT, API) every time consent is granted or
changed. A blank on every single record means there has never been a consent event of any kind on any of them.
And we have not been marketing to them. Direction verified from the
From Number and To Number on every SMS event: WKY8He Received Text Message (us to customer) “Received Text
Message”, which is the metric for one of our marketing texts landing on a handset, returns
zero events across roughly 240 sampled pool profiles. Klaviyo also refuses to include a profile with
can_receive_sms_marketing: false in a send at all, so this is platform-enforced rather than
something we have been getting away with. That is a sample rather than a full census, but the mechanism backs
it up.
One naming trap worth recording. The metric RV6gt2 Sent Text Message (INBOUND: customer to us) is called
“Sent Text Message” and it is inbound: Klaviyo names it from the profile's point of view, so
it means the customer sent us a text. On our sample, From Number was our own toll-free
number in 0 of 20 cases. Reading that metric as us sending is the obvious mistake and it inverts the
entire picture.
20,852 of the 39,918 have bought from us, and checkout captures a phone for delivery. The Shopify
integration carries form_settings.shopify_visitor_api.sync_SMS_consent: true, so those numbers
sync onto the Klaviyo profile. A number given to receive a shipping notification is transactional data and it
correctly arrives with no marketing consent. Nothing here is a breach; it is simply a large number of people
handing us a phone number in a context that cannot be used for marketing.
This is the one the thank-you page SMS opt-in is for, and that is the right fix: it puts an explicit, disclosed marketing ask at the exact moment we already have the number and the customer's attention, instead of hoping a transactional field can be repurposed later. It converts source 1 from a dead end into a capture point.
Someone typed a real number into the SMS step, Klaviyo wrote it to the profile at submit, and the
confirmation was never completed, so consent never closed. Already covered in the capture-scope report and
fixed when VdWm2S On-Page SMS Subscribers went single opt-in. Completion on typed numbers went from 41.2% to 82.7%.
This one was not known and it is the biggest of the three. Between 1 June and 21 August,
5,004 unique phone numbers texted our toll-free number with the tap-to-text opt-in message, and
Klaviyo classified 5,002 of them as Message Type: unrecognized, intent
Other. We auto-replied and granted no consent. They did every single thing we asked of them.
The cause is in the message body. The pre-filled text read “Send this text to subscribe to recurring automated personalized marketing alerts (e.g. special promotions, cart reminders) from Klaviyo Library (ref:…)”. Klaviyo's inbound parser matches keywords, and that sentence does not contain the keyword JOIN that the form declared. So the opt-in arrived as unparseable prose.
Proof that the keyword machinery itself works: over the same window 2,261 inbound texts were
correctly classified subscribe, and 2,199 of those were the literal string
YES. Short keyword, recognised. Long sentence, discarded.
This also corrects the previous report. I attributed the 0.9% mobile completion rate to shoppers not bothering to send the text. Roughly seven in ten of them did send it: 5,004 unique numbers texted us against 7,202 mobile actions on the SMS step in the same period. The SMS collapse was not reluctance. It was a keyword that never matched.
The recoverable 5,850 split by whether we ever got the digits. They need different asks.
Group B is the bigger surprise and the bigger prize. It is 82.6% of the
recoverable cohort and it is invisible to the segment I built last week, because that segment requires a phone
number on the profile. These 4,830 people are additive to the 19,970 in
RCm4nZ SMS Recovery · phone on file, never SMS-opted-in, email-reachable, not a subset of it.
Names, emails and phone numbers are masked on this page. Vercel Authentication is not available on our plan for production, so this URL is public to anyone holding it. The unmasked roster is local only, at reports/sms-gap-cohort.html and reports/sms-gap-cohort.csv. Counts and revenue are unmodified.
July is the bulk, which is exactly when the broken mobile path was at full volume.
2,265 of the 5,850 have bought from us before, carrying $281,310 of historic revenue. The other 3,585 have never ordered, so for them an SMS opt-in is the first commercial relationship rather than a deepening of one.
The thirty-five highest-value customers in the cohort. Note how many show no number captured: that is the mobile path, and it is why this group could not be found by looking at phone numbers.
| Person | Number we hold | Device when they tried | Region | Orders | Revenue | Tried on |
|---|---|---|---|---|---|---|
| Gary B.g**********@yahoo.com | none captured | MOBILE | Kentucky | 9 | $2,309 | 2026-07-22 |
| John S.k******@aol.com | +1423*****97 | MOBILE | Tennessee | 10 | $2,139 | 2026-07-26 |
| Jason D.s***************@gmail.com | none captured | MOBILE | Texas | 23 | $2,102 | 2026-07-03 |
| Norman L.l*******@casscomm.com | +1309*****52 | DESKTOP | Illinois | 12 | $1,625 | 2026-07-30 |
| Stephen F.s**************@yahoo.com | +1419*****41 | DESKTOP | Ohio | 7 | $1,567 | 2026-07-04 |
| Francisco A.f**********@yahoo.com | +1650*****27 | MOBILE | California | 12 | $1,549 | 2026-07-24 |
| Amy C.a***********@msn.com | +1201*****01 | MOBILE | New Jersey | 16 | $1,507 | 2026-07-20 |
| Zadekiel S.m**********@yahoo.com | +1773*****49 | MOBILE | Illinois | 13 | $1,357 | 2026-07-17 |
| Clinton W.c******@hotmail.com | none captured | MOBILE | British Columbia | 5 | $1,191 | 2026-07-22 |
| Philip S.d*****************@gmail.com | none captured | MOBILE | Florida | 8 | $1,180 | 2026-07-04 |
| Brandy B.b**************@gmail.com | none captured | MOBILE | Oregon | 12 | $1,107 | 2026-07-17 |
| Pauline R.p*******@gmail.cim | none captured | MOBILE | Oregon | 17 | $1,031 | 2026-08-10 |
| Richard G.r******@teamgoodley.co.uk | none captured | MOBILE | England | 8 | $1,014 | 2026-08-13 |
| Timothy J.t******@att.net | +1630*****36 | DESKTOP | Ohio | 15 | $926 | 2026-07-01 |
| Brian M.t********@gmail.com | none captured | MOBILE | Tennessee | 13 | $898 | 2026-08-05 |
| Sandi C.b**********@gmail.com | +1864*****35 | MOBILE | South Carolina | 6 | $821 | 2026-07-11 |
| Wayne M.m********@hotmail.com | +1931*****59 | DESKTOP | TN | 12 | $809 | 2026-07-22 |
| PENNEY H.p***********@aol.com | +1320*****79 | DESKTOP | Minnesota | 2 | $794 | 2026-08-01 |
| Christian M.c****************@protonmail.com | none captured | MOBILE | Texas | 4 | $789 | 2026-07-24 |
| Sharon A.s*********@gmail.com | none captured | MOBILE | Tennessee | 3 | $780 | 2026-07-03 |
| Jason E.j*********@gmail.com | none captured | MOBILE | Massachusetts | 6 | $778 | 2026-08-05 |
| Brett L.l*********@comcast.net | +1847*****51 | MOBILE | Illinois | 8 | $738 | 2026-07-08 |
| Dena B.d********@msn.com | none captured | MOBILE | Louisiana | 12 | $736 | 2026-08-16 |
| Adelyn K.a*************@gmail.com | none captured | MOBILE | Wisconsin | 5 | $704 | 2026-08-15 |
| Richard K.r******@gmail.com | none captured | MOBILE | Pennsylvania | 7 | $698 | 2026-08-08 |
| Doug E.e********@gmail.com | none captured | MOBILE | Oregon | 2 | $681 | 2026-08-04 |
| Melissa G.m**********@gmail.com | +1623*****61 | MOBILE | Arizona | 4 | $660 | 2026-07-07 |
| CESAR T.c*************@gmail.com | +1631*****92 | MOBILE | NY | 5 | $656 | 2026-07-12 |
| Jonni D.j******@hotmail.com | none captured | MOBILE | Texas | 19 | $655 | 2026-08-01 |
| Dillon A.d************@gmail.com | +1907*****93 | DESKTOP | Alaska | 5 | $649 | 2026-07-07 |
| Robert C.f*********@gmail.com | none captured | MOBILE | Texas | 2 | $643 | 2026-07-09 |
| Steven R.r***********@gmail.com | none captured | MOBILE | South Carolina | 9 | $634 | 2026-08-05 |
| Paul E.p******@gmail.com | none captured | MOBILE | Texas | 6 | $609 | 2026-07-25 |
| robert c.r********@gmail.com | +1386*****44 | MOBILE | New York | 7 | $601 | 2026-07-17 |
| Dale W.d*************@proton.me | none captured | MOBILE | Texas | 7 | $597 | 2026-08-13 |
One page, one field, sent to them by email. Here is why that shape and not another.
A static page can write a phone number straight into VdWm2S On-Page SMS Subscribers with no server, no auth and no
Klaviyo Forms build, using the public client endpoint and our public company id WdwJQj:
Two things I confirmed by probing it. First, phone_number is accepted on the client
endpoint, so this genuinely captures numbers rather than just emails. Second, and this matters more than it
looks: the endpoint rejects a number that cannot receive SMS, returning
“The phone number provided either does not exist or is ineligible to receive
ChannelType.SMS”. So we get carrier-level validation at the moment of submit, for free.
That is the direct answer to the typo risk we took on when VdWm2S On-Page SMS Subscribers went single opt-in. This page
cannot accept a junk number, which the storefront popup's plain phone field can.
A working build of exactly this page is deployed alongside this report at /claim. It is live-capable and noindexed. The offer line is a marked placeholder, because I have not been given an offer to promise.
| Option | Verdict | Evidence |
|---|---|---|
| Klaviyo's hosted subscribe page | Dead surface | subscribe_page_submit is 0 in every month from April to August, against 8 to 43 views a month. It is reachable and it has never converted anyone. |
| The existing “non-SMS subscriber” draft popups | Not usable | WgtNmQ BSS - Not subscribed to SMS, WenJci and TamScx SMS POPUP are all last updated 15 Feb 2024 and built in Klaviyo's pre-migration blocks schema, not the current components one. They are a reference, not an asset. |
| Wait for them on the storefront popup | Second, not first | It works now, at 82.7% completion, but it asks for the email first and these people are already subscribers. It also needs them to come back. Good as a passive net, not as the campaign. |
| Text them | Illegal | No consent on record for any of them. For Group B we do not even have a number. |
T4qceY submitted_form_step is rejected as a metric id in the segments API. So it is a static list:
SRLmDN “SMS Gap Recovery - tried Jun-Aug 2026 (never confirmed)”,
5,850 profiles, verified. I added them by list membership only, which does not touch
consent and fires no confirmation emails. Checked before and after: no live flow triggers on it, so
nothing auto-sent. A 100-profile sample reads 100% email SUBSCRIBED and 100% SMS
NEVER_SUBSCRIBED, which is exactly the intended audience./claim I could not write. Whatever it
is, it has to be worth typing ten digits for, and it has to be honoured by a code that actually exists./claim. No
product education, no bundling it into a promo. The subject should reference that they already started this,
because they did, and that is the only thing that makes this email different from a cold SMS ask.On pre-filling the number for Group A: we could pass the 1,020 known numbers into the page as a URL parameter so they only have to tap confirm. I would not. It puts a phone number in a query string, which Vercel and every intermediary logs, and a number typed at the moment of consent is a cleaner consent record than one we asserted on their behalf. Ten digits is a low price for a defensible record.
Four things asked, answered in order.
Yes, and we already do it at scale. It does not help. Holding a number and being allowed to text it are two separate things, and we are only short of the second one. The 39,918-profile pool in the previous report is numbers captured without consent. Group A of this cohort is 1,020 numbers we captured without consent. The digits were never the bottleneck.
If we wanted more digits without an opt-in, the legitimate route is Shopify order records. 2,265 of these 5,850 people are existing customers, and checkout captures a phone for delivery. That would likely fill in a large share of Group B. I could not size it: the Shopify Admin token expires every 24 hours and the current one is dead, so this needs a fresh token and a one-hour pull.
But a number taken from a shipping field carries no marketing consent, and texting it is a TCPA
violation, at $500 to $1,500 per message. In a 350-profile sample of the wider pool, Klaviyo had already
flagged two people as KNOWN_LITIGATOR. So enrichment would give us 4,830 more numbers we
still cannot use.
The one place enrichment genuinely earns its keep is friction: if we know the number, the recovery email can say “confirm the mobile ending 47” instead of asking for ten digits. That is a real conversion lever and worth the token pull. It is not a way around consent, and there is no way around consent worth having here. Get the consent and the number arrives with it, in the same tap.
One dedicated campaign to SRLmDN SMS Gap Recovery - tried Jun-Aug 2026 (never confirmed), single purpose, one CTA, then one reminder to
people who did not click. Explicitly not folded into a promo or a newsletter, for two reasons. The only
thing that makes this email legitimate rather than cold is that it references something they started, and
that argument does not survive being bundled with a sale. And a single-purpose send gives a clean conversion
read, which is the whole point of running this cohort before the bigger list.
Sequence: send to a 1,000-person slice first, weighted to the 2,265 existing customers. Read the real opt-in rate. Then decide on the remaining 4,850. The email itself still needs to go through the framework audit and the repo pull; I have not drafted it, and it should not be improvised.
/claim as it stands is a working prototype, not the production page. The mechanism is
proven and the code is final. What has to change before it goes in an email:
vercel.app onto blackforestsupplements.com. This is the one
non-negotiable. Putting an unfamiliar domain behind the only CTA in an email to 5,850 people costs us
deliverability and reads as phishing to anyone paying attention. The page is a single self-contained HTML file
with inline JS and no build step, so it drops into a Shopify page template as-is. The Klaviyo client endpoint
is called from the browser and needs no server, so hosting it first-party changes nothing about how it works.VdWm2S On-Page SMS Subscribers with SUBSCRIBED and a custom_source of
“SMS gap recovery”, so the cohort stays attributable afterwards.After the campaign, the same page is the destination for the 19,970 in RCm4nZ SMS Recovery · phone on file, never SMS-opted-in, email-reachable, and the
same JS is what a phone-only on-site popup would do. It is one asset serving all three.
Yes, we have an email for all 5,850, which is the whole reason this cohort is reachable.
List SRLmDN SMS Gap Recovery - tried Jun-Aug 2026 (never confirmed) is created and populated.
| Check | Result |
|---|---|
| Profiles on the list | 5,850, matching the roster exactly |
| Added how | List membership via the relationships endpoint. Does not write consent, sends no confirmation email. |
| Live flows triggering on it | Zero, checked across all 54 flows in the account. Nothing auto-fired. |
| Email reachability (100 sampled) | 100% SUBSCRIBED |
| SMS state (100 sampled) | 100% NEVER_SUBSCRIBED, so nobody already opted in is being re-asked |
It is a static list, so it will not refresh itself. Anyone on it who opts in through any route stays on it until removed, which means suppress against SMS consent at send time rather than trusting the membership.
Smaller base than the wider pool, and it should convert better. Both things are true.
model That is a one-off recovery, not a monthly rate, and the benchmark is Klaviyo's for on-site phone-only forms rather than ours for an email-driven landing page. I would treat the low end as the planning number.
Why run this before the bigger list anyway. The 19,970 in
RCm4nZ SMS Recovery · phone on file, never SMS-opted-in, email-reachable is a larger prize on paper. But most of those numbers arrived at Shopify checkout, from
people who never asked to be texted. This cohort is the opposite: 5,850 people who walked up to the
SMS step and pressed the button. If they will not opt in, the wider pool certainly will not, and we will have
learned that for a tenth of the send volume. Run this one first as the read on the whole idea.
Every live form on the account, checked for whether a submit actually results in a consent record. This is the “never let this happen again” pass, and it found things.
Tap-to-text is gone from every live form. I pulled all 10 live form definitions
and searched case-insensitively for a subscribe_via_sms action and for the string
“Klaviyo Library”: zero of ten carry either. The mechanism that produced the
5,004-person failure cannot fire from any pop-up today.
The traffic has stopped too. Since the fix went live on 18 August, only 7 tap-to-text opt-in messages have arrived, all of them on the 18th itself, and none on the 19th or 20th. The bleeding is over.
But the parser fault was never fixed, only starved of traffic. All 7 of those late
arrivals were still classified unrecognized. We removed the button, not the bug. And
9 draft forms still carry a live tap-to-text action, 8 of them still carrying the
“Klaviyo Library” body: XBdpzj and Y2qrW7 (both “Futuristic tap-to-text”), TamScx “SMS POPUP”, S39mpj “Christmas SMS”, XjmVsc “Exclusive Spermidine Launch List”, T8ZgSM Multi-step email & SMS -- CashBack A/B Test “Multi-step email & SMS -- CashBack A/B Test”, WgtNmQ “BSS - Not subscribed to SMS”, WbnJAj “PROMO - Multi-step email & SMS”, TLCJWj Multi-step email & SMS “Multi-step email & SMS”. Publishing any one of them recreates the
collapse exactly. They should be corrected or deleted rather than left as landmines.
A note on how nearly I missed that. My first scan counted the uppercase
SUBSCRIBE_VIA_SMS that the current form schema uses and reported zero drafts affected. The legacy
schema these drafts are built in writes it lowercase as subscribe_via_sms, so the real answer was
nine. Any recurring check has to be case-insensitive and has to cover both schemas.
Nothing in a form points at it any more, but +1 888 302 6840 still accepts inbound keywords and
SUmgWj SMS Subscribers is still gaining profiles. Anyone working from a saved message, an old screenshot or a
cached page still lands in a list no flow listens to.
Four live forms submit to a list that no longer exists. The list ID in the form
action returns 404 from both the lists and the segments endpoints. A submit on these goes nowhere:
no list, no consent, no flow. This is the same class of silent failure as the tap-to-text bug.
There are 10 live forms on the account. Seven of them collect a phone number. Those seven are the only ones that can produce an SMS consent record, so they are what matters here. Verified against the live form definitions and the list settings on 21 August; nothing had been changed yet at the time of this pull.
| Pop-up that collects a phone number | Writes into | Form setting consent_type | List setting opt_in_process | Measured outcome |
|---|---|---|---|---|
Email + SMS (sign-up form)the main welcome pop-up · STUCB3 Email + SMS (sign-up form) |
On-Page SMS SubscribersVdWm2S On-Page SMS Subscribers |
PROMOTIONAL ONLY | single opt-in | 88.1% subscribedmeasured 19-21 Aug |
Countdown Sale - Black Seed OilVqpsb7 Countdown Sale - Black Seed Oil |
On-Page SMS SubscribersVdWm2S On-Page SMS Subscribers |
PROMOTIONAL ONLY | single opt-in | Same list, same behaviour |
Countdown Sale - NAD+ BOGOTYjzAx Countdown Sale - NAD+ BOGO |
On-Page SMS SubscribersVdWm2S On-Page SMS Subscribers |
PROMOTIONAL ONLY | single opt-in | Same list, same behaviour |
NAD+ EARLY ACCESSlive on the BFMD Florida launch · VCfHT8 NAD+ EARLY ACCESS |
BFMD — Florida SMS (Jul 2026)SWAHz2 BFMD — Florida SMS (Jul 2026) |
SINGLE STEP TRANS + PROMO | double opt-in | 75% subscribedthe double opt-in is NOT gating it |
Sleepy COCOA META lead-gen campaignVMcxPc Sleepy COCOA META lead-gen campaign |
Sleepy Cocoa META SubscribersSQTjGy Sleepy Cocoa META Subscribers |
not set (legacy) | double opt-in | Unmeasured · ~0 traffic |
EMBED FORM - Meta Sleepy Lead Gen - Collect SMSVDXheq EMBED FORM - Meta Sleepy Lead Gen - Collect SMS |
Sleepy Cocoa META SubscribersSQTjGy Sleepy Cocoa META Subscribers |
not set (legacy) | double opt-in | Unmeasured · ~0 traffic |
Cocoa Relaunch Meta SMS Lead genS4T6FR Cocoa Relaunch Meta SMS Lead gen |
Nothing. The list was deletedXAPZRJ DELETED — does not exist returns 404 |
not set (legacy) | no list exists | Nothing · the submit vanishes |
The main welcome pop-up and both countdown sale pop-ups write into On-Page SMS Subscribers, single opt-in since 18 August, measured at 88.1% subscribed. NAD+ EARLY ACCESS sits on a double opt-in list but measures 75% subscribed, so that setting is not gating it. Four of the seven are fine.
Cocoa Relaunch Meta SMS Lead gen is the only outright break: it collects a required phone number into
a list that no longer exists, so every submit is discarded. The two Meta Sleepy forms sit on a double opt-in
list with no consent_type set and near-zero traffic, so they are unmeasured rather than proven
broken. Check them by consent outcome before changing anything, which is the lesson from the
VCfHT8 NAD+ EARLY ACCESS correction above.
Listed for completeness. None of them can affect SMS consent either way, but all three submit into a list that has been deleted, so their email captures are being discarded too.
| Live pop-up | Writes into | State |
|---|---|---|
BE NOTIFIED WHEN IT'S BACK!back-in-stock · XGMwtT BE NOTIFIED WHEN IT'S BACK! | XGcgrx DELETED — does not exist | List deleted · 404 |
NMN Out Of StockSrnri4 NMN Out Of Stock | WZMgtJ DELETED — does not exist | List deleted · 404 |
LEAD GENS4WCnA LEAD GEN | T77WJb DELETED — does not exist | List deleted · 404 |
Correction, 21 August: I had this form down as leaking and it is not. I previously
reported that VCfHT8 NAD+ EARLY ACCESS converted 750 phone submits into 89 opt-ins, an 11.9% completion rate. That
number was wrong and the method that produced it was wrong. I counted new
“Subscribed to Text Messaging Marketing” events against total submits, which badly
undercounts any form whose visitors are largely already subscribers, because no new subscription event fires for
someone who is already in.
Checking the consent state on the profiles directly instead:
135 of 180 sampled phone submitters on VCfHT8 NAD+ EARLY ACCESS are marketing-subscribed, which is 75%. The
double opt-in setting on SWAHz2 BFMD — Florida SMS (Jul 2026) is not blocking SMS marketing consent on this form.
The form carries a PROMOTIONAL_SMS_CHECKBOX labelled “Check this box to receive
promotional marketing texts”. Over 1 to 20 August it took 786 submits, and the checkbox came back
ticked 509 times and unticked 273 times. So about 35% hand over a phone number without ticking the
promotional box.
Those people get transactional consent only. The profile reads
sms.transactional.consent = SUBSCRIBED and sms.marketing.consent = NEVER_SUBSCRIBED,
which is exactly the pattern in the sample: 25 of 180 sit in that state. That is the form working as
designed, not a fault, and it is a legitimate ongoing contributor to the pool. If we want more of that 35%,
the lever is the checkbox copy and placement, not the opt-in setting.
Because that measurement error affected one number, I re-checked the headline the same direct way: take the phone numbers typed into the SMS step and read the consent state on those profiles, rather than counting subscription events.
| Cohort of numbers typed into the SMS step | Marketing SUBSCRIBED | NEVER_SUBSCRIBED | UNSUBSCRIBED |
|---|---|---|---|
| 1–17 Aug, while On-Page SMS Subscribers was double opt-in | 43.5% | 38.1% | 17.7% |
| 19–21 Aug, after it went single opt-in | 88.1% | 5.8% | 5.4% |
260 profiles sampled per period. The finding holds and is slightly stronger than first reported: the
share left with no consent fell from 38.1% to 5.8%. It also matches the event-based estimate of 41.2% to 82.7%
closely enough to confirm both, so that comparison was sound even though the VCfHT8 NAD+ EARLY ACCESS one was not.
Why the two forms behave differently under the same kind of setting is the distinction in the next section, and it is the thing worth internalising: the list setting and the form setting are not the same control.
Every fault on this page is detectable from the API. Every one of these faults is
detectable from the API in about two minutes: for each live form, resolve the action's
list_id, assert it exists, assert its opt_in_process, and assert
SUBSCRIBE_VIA_SMS does not appear. That is worth running on a schedule rather than after the next
collapse. Nothing on this page needed a person to notice a revenue dip first.
Two independent controls with similar names. Reading one and reporting the other is exactly the mistake corrected above, so this is written down properly.
What the phone field is allowed to grant. Lives on the PHONE_NUMBER component as
channel_settings.sms.consent_type. In the Klaviyo editor this is the dropdown reading
“Single step…” or “Multi step…”.
“Single step” here means one step in the form, nothing more. It says nothing about whether a confirmation is required afterwards.
Whether an off-platform confirmation is required before consent counts. Lives on the list as
opt_in_process: single_opt_in or double_opt_in. Set in the list's own
settings, not in the form.
A form can be “single step” while the list it writes into is “double opt-in”. Both statements are then true at once, which is how one form ended up described two ways.
| Option in the editor | Stored value | What one submit grants | What you can then send | Which of our pop-ups use it |
|---|---|---|---|---|
| Single step – Promotional only | PROMOTIONAL_ONLY | Marketing consent only | Campaigns and marketing flows. No order or shipping texts via Klaviyo | Email + SMS (sign-up form), Countdown Sale - Black Seed Oil, Countdown Sale - NAD+ BOGO |
| Single step – Transactional only | TRANSACTIONAL_ONLY | Transactional consent only | Order and shipping notices only. Marketing is permanently off for anyone captured this way | None, and keep it that way |
| Single step – Transactional & promotional | SINGLE_STEP_TRANSACTIONAL_PROMOTIONAL | Both, in one action | Everything | NAD+ EARLY ACCESS |
| Multi step – Transactional & promotional | MULTI_STEP_TRANSACTIONAL_PROMOTIONAL | Both, but the ask is split across two steps in the form | Everything | None |
The trap in that table is “Transactional only”. It reads like a milder version of the others. It is not: every number a form collects under that setting is permanently unavailable for marketing, with no confirmation step to blame and nothing to recover afterwards. If a pop-up were ever switched to it, it would quietly manufacture exactly the pool this report is about. No form of ours uses it today, and none should.
consent_type sets what a form may grant. A PROMOTIONAL_SMS_CHECKBOX
component decides whether the promotional half is actually granted on a given submit. NAD+ EARLY
ACCESS has one; the three PROMOTIONAL_ONLY pop-ups do not, and do not need one.
So a form set to “Transactional & promotional” with the box left unticked produces a transactional-only subscriber. That is the real mechanism on that form, and it accounts for 35% of its submits.
NAD+ EARLY ACCESS is the only form we own set to “Single step – Transactional &
promotional” with a PROMOTIONAL_SMS_CHECKBOX, which makes it a clean natural
experiment. Same form, same traffic, same disclosure. The only difference is whether the shopper ticked the box.
I read the consent state off the profile for 170 numbers in each arm.
| Arm | Submits | Marketing SUBSCRIBED | Marketing NEVER_SUBSCRIBED | Transactional SUBSCRIBED |
|---|---|---|---|---|
| Checkbox ticked | 432 | 88% | 6% | 97% |
| Checkbox left unticked | 219 | 47% | 38% | 89% |
The checkbox is worth 41 percentage points of marketing consent, and the share left with no consent at
all goes from 6% to 38%. Note that the unticked arm still reaches 47% subscribed, because many of those people
were already subscribers from somewhere else; the incremental damage is the 38% who end up
NEVER_SUBSCRIBED.
Transactional consent is roughly the same in both arms (97% against 89%), which is further evidence that the transactional half is not really being driven by this form setting at all.
34% of shoppers do not tick it. 219 of 651. That is the cost of putting the promotional ask behind an extra deliberate action.
No, on this evidence. Blend the two arms of the experiment and the trans-and-promo-plus-checkbox configuration returns 74% marketing consent overall ((432×88% + 219×47%) ÷ 651). The main pop-up's promotional-only configuration, with no checkbox at all, returns 90%.
| Configuration | Checkbox | Marketing consent achieved | Transactional |
|---|---|---|---|
| Promotional onlyEmail + SMS (sign-up form), both Countdown Sale pop-ups | None needed | 90% | 89% |
| Single step – Transactional & promotionalNAD+ EARLY ACCESS | Required, and 34% skip it | 74% blended | 89–97% |
So the trade we are actually making by staying on promotional-only is not transactional reach. It is simpler than that: promotional-only needs no checkbox, and every checkbox loses a third of the people who see it. Adding one to the main pop-up to pick up a transactional consent we already have at 89% would cost roughly 16 points of marketing consent. That is the wrong trade.
Where this does matter is the thank-you page. If that page is meant to carry order and shipping notifications, decide the setting from a test on that page rather than inheriting either of these. And if the aim there is marketing consent, the evidence here says ask for it directly with no checkbox in the way.
Yes on the legal posture, with one genuine exposure and one unmeasured cost. Single opt-in is lawful in
the US where express written consent is captured, and the disclosure under the phone field is what provides it. I
read the disclosure on all three PROMOTIONAL_ONLY pop-ups: each names Black Forest, says marketing
text messages, names autodialer, states consent is not a condition of purchase, gives STOP and HELP, states msg
& data rates and that frequency varies, and links Privacy and Terms. That is complete.
The real exposure is not typos, it is wrong numbers. A shopper who mistypes one digit can subscribe a
stranger, and that stranger has no relationship with us and every reason to complain. Double opt-in was the
control that caught it and single opt-in has nothing in its place. The answer is not to revert, it is inline
validation: our /claim page gets carrier-level validation free from the Klaviyo client endpoint,
and the storefront pop-up's plain phone field has none.
The unmeasured cost is deliverability. Junk numbers now enter and we pay to text them until they hard fail. Still not measurable, because no campaign has hit the post-18-August cohort yet. Compare that cohort's failure rate against the pre-18-August one once one has.
On the transactional question, see the next card. It is answered, and the answer is that there is no separate transactional opt-in for almost anyone.
I said promotional-only costs us the transactional opt-in, then that it does not, then that the mechanism was unexplained. It is now traced, and both earlier statements were incomplete.
For almost every profile, transactional consent is never granted. It is a mirror of marketing consent.
On profiles sourced by the promotional-only pop-ups the transactional block reads
consent_timestamp: null and method: null while still saying
SUBSCRIBED. No transactional consent action ever happened; the field simply reflects the marketing
state.
| Sample | n | Transactional mirrors marketing | Has a real timestamp + method |
|---|---|---|---|
| On-Page SMS Subscribers members, mixed states | 400 | 399 | 38 |
The recovery pool, marketing NEVER_SUBSCRIBED | 110 | 109 | 1 |
| Combined | 510 | 508 = 99.6% | 39 |
Marketing SUBSCRIBED gives transactional SUBSCRIBED. Marketing
UNSUBSCRIBED gives transactional UNSUBSCRIBED on 182 of 182 in the sample.
Marketing NEVER_SUBSCRIBED gives transactional NEVER_SUBSCRIBED. It tracks in every
direction.
The only real transactional records in the account come from one form. The metric RgFTui
“Subscribed to Text Messaging Transactional” reads zero every month up to June 2026, then 354
in July and 778 in August. All 781 August events carry form_id: VCfHT8 and
permission_name: sms_transactional, method form. NAD+ EARLY ACCESS is the sole
source, because it is the only form set to “Transactional & promotional”. 911 profiles now
hold one.
That record buys one specific thing: it survives a marketing opt-out. Of 212 sampled profiles in the explicit-grant cohort, all 212 carry a real transactional record, and of the 14 who have since unsubscribed from marketing, 10 kept transactional consent, which is 71%. In the derived population the same opt-out takes transactional with it every time.
| Marketing state | Derived · promotional-only pop-ups | Explicit grant · NAD+ EARLY ACCESS |
|---|---|---|
| Subscribed | Transactional subscribed | Transactional subscribed |
| Unsubscribed from marketing | Transactional lost, 182 of 182 | Transactional kept, 10 of 14 |
| Never subscribed | Transactional never | Transactional subscribed on 39 of 212 |
So the trade is real, and today it buys us nothing, because of our own flow
configuration. We do run a transactional SMS flow: XBEv2U
“[BFS][SMS] Order Shipped (Transactional)”, live since 16 June, triggered by the Shopify
metric Confirmed Shipment. Over the last 30 days it sent to 261 recipients, 259 delivered, 210
clicks.
But that flow is not flagged as a transactional message. Its definition carries
no sms_transactional permission, so Klaviyo sends it as an ordinary SMS against marketing
consent. All 261 recipients were marketing-subscribed. Anyone who opts out of marketing stops getting shipping
notifications, whether or not they hold a transactional record.
Which means the transactional consent we collect on NAD+ EARLY ACCESS is currently unused, and the transactional consent we do not collect elsewhere is currently costing us nothing. Making post-opt-out shipping notices work needs both halves: the flow flagged as transactional, and an explicit transactional consent. We have neither on the main pop-up path and only the second on one form.
The decision that follows. Do not add a checkbox to the main pop-up to chase
this; that costs about 16 points of marketing consent. If shipping texts surviving a marketing opt-out matters,
flag XBEv2U as a transactional message first and see whether the consent gap even binds, before
touching any capture form.
The people who texted us the subscribe message. Isolated, resolved against live profiles, and compared with the recovery list.
unrecognized. 5,000 resolved to a live profile.The finding that changes how this cohort has to be handled: 3,437 of the 3,648 have no email address at all. That is 94% of them. Tap-to-text creates a profile from an inbound phone number, so there was never an email step. These are phone-only profiles.
Which means SMS is the only channel that exists for them. They cannot be sent the recovery email, they cannot be sent anything else, and they are invisible to every email-keyed audience we have built. If the inbound text is not treated as their consent, these 3,437 people are simply unreachable, permanently, despite having texted us asking to be contacted.
| Resolution | Count | Note |
|---|---|---|
| Numbers that texted the opt-in message | 5,004 | The number is the identifier and we hold it |
| Resolved to a live Klaviyo profile | 5,000 | 4 had no profile |
Still NEVER_SUBSCRIBED | 3,648 | Texted us to subscribe, still not subscribed |
| … of which phone-only, no email | 3,437 | SMS is their only channel |
| … of which have an email | 211 | Reachable either way |
| Since subscribed by another route | 1,010 | Already in. Leave alone |
| Since unsubscribed | 342 | Exclude. They opted out after the fact |
| Existing customers among the never-subscribed | 158 | $29,254 historic revenue |
The recovery list is SRLmDN, named “SMS Gap Recovery - tried Jun-Aug 2026 (never
confirmed)”, holding 5,850 email-reachable people who acted on the SMS step and never completed.
| Comparison | People | Meaning |
|---|---|---|
| In both, matched on email | 162 | Remove from the recovery campaign. Asking them to sign up when they already texted us is the wrong message |
Have an email but are not on SRLmDN SMS Gap Recovery - tried Jun-Aug 2026 (never confirmed) | 49 | Missed by the session join |
| Cannot be compared: no email to match on | 3,437 | Not on SRLmDN SMS Gap Recovery - tried Jun-Aug 2026 (never confirmed) and never could be. Entirely additive. |
So the overlap is small on purpose. SRLmDN SMS Gap Recovery - tried Jun-Aug 2026 (never confirmed) is an email-keyed audience and this cohort is
overwhelmingly phone-only. These are two different populations reached two different ways, and only
162 people need suppressing between them.
Built as UUPZS9, “SMS Consent Evidence - texted opt-in, not subscribed (Jun-Aug 2026)”, holding the 3,648 never-subscribed
senders. Added by membership only, so it writes no consent and fires nothing. The 342 who later unsubscribed and
the 1,010 already subscribed are excluded.
Two operational notes, not objections. Klaviyo will not deliver to a profile reading
NEVER_SUBSCRIBED, so consent has to be written deliberately before any send; list membership alone
will not make these sendable. And the inbound event is the evidence: body, sender number and timestamp
live only in the event stream, so it should be exported and retained alongside the decision.
| Decision | Why it is yours and not mine |
|---|---|
Flip SRLmDN SMS Gap Recovery - tried Jun-Aug 2026 (never confirmed) to single opt-in? | It defaulted to double opt-in on creation. Irrelevant for sending a campaign, because email consent lives on the profile and all 5,850 are already subscribed. It only matters if a form is ever pointed at this list. UI-only setting. |
What is the offer on /claim? | The page is built and functional with a placeholder. I will not invent a discount or a code. |
| Does the recovery email need the framework audit? | Yes, and I have not drafted it here. It is a real send to 5,850 people and should go through the framework and the repo pull rather than be improvised in a report. |
| Sign-off on single opt-in still not on record | Carried over. Every number this page captures lands on a single-opt-in list. |
| Include the 669 who unsubscribed from SMS? | My answer is no. They opted in and left. Re-asking is the kind of thing that produces complaints. |
Correction carried forward. The previous report said mobile tap-to-text abandoners
were “permanently unrecoverable”. They are not. Their phone numbers are unrecoverable; the people are
not, and there are 4,830 of them in the recoverable cohort. I reached that wrong conclusion by reading
the empty submitted_fields on the event and stopping there, instead of joining on
cid.