Email capture
Turn taps on your rich fallback page into an owned email list — consent-first by design, always-204 on the public endpoint, and erasure that is never paywalled.
Email capture
Your rich fallback page already catches the taps that can't open the
app. Email capture adds one small form to it — "Get updates from {your name} ⚡" — so a
visitor who was about to bounce can hand you their email instead.
That email lands in Audience → Contacts in your dashboard. It's yours: exportable as CSV, pushed to your own endpoint by webhook, deletable at any time. No algorithm sits between you and it.
Email capture is available on Hero and up, and rolls out behind the audience-capture
feature flag.
Turn it on
- Make sure the link has its rich fallback page enabled.
- On the link, switch on Collect emails.
- That's it. The next visitor who lands on the fallback page sees the form.
The form only renders when all three are true: your plan includes audience capture, the
audience-capture flag is on for your workspace, and the link has Collect emails
switched on. Otherwise the fallback page renders exactly as before.
What the visitor sees
A heading naming you, one email field, and a consent checkbox that is unchecked by default:
Get updates from Ada's Studio ⚡ Drop your email — no app needed.
☐ I agree to receive emails from Ada's Studio. Unsubscribe anytime.
There's also a hidden website field the visitor never sees — a honeypot. Bots fill it;
humans don't.
The public endpoint
The form posts to a public, unauthenticated endpoint:
It always returns 204
Every single path returns 204 No Content. Malformed body, honeypot filled, consent missing,
slug that doesn't exist, capture switched off, plan without the feature, email already on your
list — all 204.
That's deliberate. A public sink that answered differently for "already subscribed" would be
an email-enumeration oracle: anyone could probe whether [email protected] is on your list.
So the endpoint tells the caller nothing at all, and the form thanks the visitor either way.
Two guardrails ride along with it: emails are capped at 254 characters (the RFC 5321 maximum), and anything in the honeypot field is dropped on the spot.
Consent is required, and it's ours to word
consent must be exactly true. Anything else — false, missing, a string — and the
submission is dropped before anything is stored. There is no "implied consent" path.
The consent text is written by the server, never sent by the client. When a contact is stored, Zippy records the exact sentence the visitor agreed to, with your workspace name baked in:
That string is stored per-contact and rides along in your CSV export, so months later you can show precisely what each person agreed to. The visitor always knows who is getting their email — you, by name — because the form and the stored consent both say so.
Your contacts
GET /api/audience returns your newest contacts (up to 500) plus a total count:
sourceSlug tells you which link earned the contact, so you can see which drop, reel, or
campaign is actually building your list. country is best-effort from the edge geo header and
is null when unknown.
Past 500 contacts, use the export.
Export
GET /api/audience/export.csv hands you the whole list, oldest first:
Cells are formula-neutralized, so a captured email can't turn into a spreadsheet formula when someone opens the file in Excel. Take that CSV anywhere — your ESP, your CRM, a text file on your laptop. It's your list.
Live delivery
Every genuinely new contact also fires a contact.captured webhook
to your own endpoint, email included, so new contacts can land in your CRM the second they
arrive. A re-submit of an email already on your list is a silent no-op and sends nothing.
Erasure is never paywalled
DELETE /api/audience/:id removes a contact. It has no tier gate and no flag gate — it
works on every plan, including Free, including a workspace that downgraded away from audience
capture yesterday.
This is on purpose. Erasure is a data-subject right, not a feature. Somebody asking to be removed from your list should never hit a paywall, and a creator honouring that request should never have to upgrade to do the right thing. Building capture on a plan gate while leaving deletion open is the only shape that isn't hostile.
Deleting a contact deletes the row — email, source, country, consent text, all of it.
Who's responsible for what
You are the data controller for the emails you collect; Zippy is the processor. Practically:
- Zippy stores the consent wording, the source link, and the timestamp so you have a record.
- You decide what you send, and you honour unsubscribes and deletion requests.
- The form promises "updates from you." Sending something else breaks the promise the visitor actually agreed to.
Double opt-in isn't implemented yet — it's a planned upgrade, and we'd rather say that than imply a confirmation email goes out today.
Notes
- Hero and up, behind the
audience-captureflag. Deletion is every plan, always. - Capture only runs on default-host links (the same set the fallback page serves).
- Your links keep redirecting forever whether or not anyone ever fills in the form — permanence isn't affected by anything on this page.
- Pairs with audience segments: segments tell you who's tapping, capture gives you a way to reach them, and broadcasts is where you actually reach them.
FAQ
How do I collect emails from my link in bio?
Enable the rich fallback page on the link, then switch on Collect emails. Anyone who taps your link and can't be sent straight into a native app lands on your fallback page and sees a "Get updates from you" form. Their email goes to your Audience list, exportable as CSV.
Does Zippy tell me if the email was already on my list?
No — the public capture endpoint returns 204 for every outcome, including duplicates. That's
what keeps it from being used to test whether a given address is one of your subscribers. Your
dashboard count and export show you the truth; the public endpoint reveals nothing.
Can I collect emails without a consent checkbox?
No. A submission without consent: true is discarded before anything is written. There's no
setting to turn it off, because a list built without consent is a liability, not an asset.
What happens if someone asks to be deleted?
Delete the contact from Audience → Contacts, or call
DELETE /api/audience/:id. It works on every plan — erasure is never gated behind an upgrade.
Where do captured emails go?
Your dashboard, your CSV export, and your webhook endpoint. You can also email them from Zippy directly — see broadcasts, which enforces the consent record stored here and attaches a one-click unsubscribe to every message. Zippy never uses your contacts for anything else.
Read more
- Blog: Your list is the only audience you actually own
- Changelog: Email capture
- Sibling feature: Audience segments · the segments story
- Where the audience comes from: Instagram DM automations turn a comment into a tap; this page turns that tap into a contact you own.
- What to do with it: broadcasts · the broadcasts story