Someone installs AntiFreeze, turns on alerts, and gets nothing. Maybe their phone put the app to sleep to save battery. Maybe they tapped past the notification permission during setup. Either way they need to ask a person, and the second they do, they have to decide how much they trust whoever is on the other end of that message.
AntiFreeze is the app I launched in March for reporting and receiving alerts about immigration enforcement activity. It has around 7,900 users now. People write in with install problems, questions about why alerts stopped, requests from community organizations that want partner access, and the occasional press inquiry. Until this month they had one way to reach me, which was email.
Every company you deal with runs a support channel. A phone tree, a WhatsApp business account, a Zendesk form, a chatbot that takes four turns to admit it can’t help. Those are fine when the worst case for a leaked ticket is somebody selling your address to a mattress company. The math changes for this app. A support ticket for AntiFreeze proves that one identifiable person, at one identifiable moment, was using software for tracking ICE. The message itself might say nothing more interesting than “push notifications stopped working.” The record of the contact is the exposure, and the message body barely matters.
That ruled out the normal options. A hosted helpdesk means a company I’ve never met keeps a permanent list of who contacted an immigration-enforcement-reporting app and when. A Google Form means Google keeps it. Our email runs through Proton, so if you write from a Proton address the whole thing stays encrypted end to end, and I don’t hold your message on anyone else’s servers. That covers people who already use Proton or who are comfortable with email. It does not cover the person standing in a parking lot who needs a fast answer and has Signal on their phone already.
So I spent two days building a support line that runs on Signal, and it went live carrying real traffic on the second day.
What the line is for, and what it absolutely is not for
The support number handles questions about the app. Installation, notifications, partner access, press.
It is not the channel for reporting an ICE sighting. Sightings go through the app. A report texted to the support number does not reach anyone in the reporter’s area, and it will sit in a queue until I read it.
I want that stated plainly, because the failure mode terrifies me. Picture someone who saw agents outside a school, pulls up a number they half-remember seeing in an article, fires off a text, and walks away believing they raised the alarm for their neighborhood. They didn’t. Nobody got that alert. The system sends an automated reply spelling this out the first time anyone messages, and I’m repeating it here because an article that implies “text this number to report ICE” would produce that exact failure at scale.
Deletion as a requirement instead of a feature
Most software keeps everything until somebody remembers to clean it up. Deletion lives in an admin panel behind a button nobody clicks.
On this line, message bodies disappear a week after the last message in a conversation, whether or not I remember, whether or not I’ve read them, whether or not the question was resolved. Attachments get erased in the same pass. I don’t hold a searchable archive of who asked me what, because I don’t want one, and because I can’t hand over what I don’t have.
Closed tickets never reopen. If you message me in September about a notification bug and again in November about something else, those are two separate tickets with two separate clocks. Your contact record persists so I know we’ve talked, but the words don’t.
The hardest part was the phone in your pocket
Erasing my own database is the easy half. I control that box and I can reason about it.
The copy sitting in your Signal app is the one that matters if your phone gets taken at a traffic stop, and I have no authority over your device at all. Signal solves this with disappearing messages, but the timer has to be set on the conversation, and for weeks it wasn’t. I found out by opening my own test thread and noticing the header said “Disappearing Messages off.” A step in my own written procedure was supposed to handle it. That step ran without any error and did nothing.
The line now sets the timer on each conversation as it starts, including conversations that already existed. Your copy expires on your phone on the same schedule mine expires on my server. A database that forgets on schedule is worth very little when the phone in someone’s pocket remembers forever.
Somebody called
Signal calls to the support number used to ring out into silence. No ticket, no reply, nothing. Someone tried to reach me and the system swallowed it.
Calls now open a ticket and send one text back explaining that the line takes text only. One text, rate-limited on purpose. Somebody redialing six times in two minutes is probably scared, and answering with six automated messages means the software is shouting at a frightened person. That was a judgment call about human beings rather than a technical decision, and it’s the kind of choice that comes up constantly once you start asking what happens to this person on their worst day.
Calling also can’t extend how long your messages live. If redialing reset the retention clock, someone could keep their own record alive by accident, and the promise in the auto-reply would be a lie.
What shows up on my lock screen
When a message arrives I get a push alert on my laptop and my phone, because I’m not going to sit refreshing a dashboard, and someone waiting on an answer shouldn’t depend on when I next check.
Those alerts carry no message content. They say “New ticket #7” and nothing else. My lock screen is visible to anybody standing behind me at a coffee shop, and notification history on a phone outlives the message that triggered it. The alert itself runs on a server I own rather than a notification service, since even content-free pings would tell an outside company the timing and volume of contacts arriving at an ICE-reporting support line, and that pattern says plenty on its own.
What this does not do
I’d rather list the gaps than let anyone assume they don’t exist.
Signal still knows a message went to that number, and when. Nothing I build changes what Signal itself can see. Cloudflare sits in the path for the dashboard, which is a trade I made for access control and for surviving attacks, and it means traffic terminates on their infrastructure. Attachments live on disk until the purge runs. Retention is a schedule rather than an instant, so your message exists for that week. If my server goes down, messages queue up at Signal and reach me late.
Calling this “secure” or “anonymous” would be marketing. The accurate version: contacting support leaves as little trace as I can manage, and what has to exist gets deleted on a fixed schedule.
It’s one guy
The dashboard supports multiple people. Nobody else is on it. Every message to that line comes to me, and I read all of them, which is fine at this size and won’t be forever. If AntiFreeze keeps growing I’ll need people I trust enough to hand an authenticated laptop to, and any one of those laptops could read every open ticket. That’s a real limitation of the design and I’d rather say so now than pretend the software solves a trust problem it can’t.
None of this is glamorous. There’s no clever cryptography in it and nothing here is novel. It’s a pile of unremarkable choices, made one at a time, by asking the same question over and over: what happens to this person if somebody hostile sees this?
Grassroots tools get built by people who care about the mission and then get handed a support inbox as an afterthought. For an app whose users have reason to fear a government agency, the support inbox is part of the safety story. It deserved the same care as the alerts.