A free U.S. phone number in your pocket. FreeLine is a mobile-first VoIP app that gives users a real U.S. phone number for calling and texting over Wi-Fi or mobile data. No carrier plan required.
The core thesis: phone numbers should feel as free and easy to get as email addresses.
The gallery below reflects the latest local iOS simulator and Android emulator captures from the refreshed glass-style native shells, including the new Aura AI receptionist concept.
Aura is a live AI receptionist for unknown inbound calls. It screens the caller first, explains who they are and why they are calling, scores risk, and tees up the best next move before the user answers. The user can take over the call, reply by text, ask Aura to clarify, or send the caller to voicemail without losing context.
I built FreeLine to understand how the TextNow product actually works. Not the surface-level features, but the telephony layer, the unit economics, the abuse controls, and what it really takes to offer a free phone number without going broke. Users download the app, sign up, choose a U.S. area code, and claim a free phone number. From there they can send and receive SMS, make and receive voice calls, and access voicemail, all from inside the app over any internet connection.
- Download the app on iOS or Android
- Sign up with email, Apple Sign-In, or Google Sign-In
- Choose a U.S. area code
- Claim a free phone number
- Call and text from inside the app
| Feature | Details |
|---|---|
| Free U.S. number | One real phone number per user, selected by area code |
| SMS messaging | Send and receive 1:1 text messages with delivery status |
| Voice calling | Outbound and inbound calls with native call UI (CallKit on iOS, ConnectionService on Android) |
| Aura AI receptionist | Screens unknown callers live, summarizes intent, scores trust, and offers take over, text reply, follow-up question, or voicemail actions before you answer |
| Voicemail | Missed calls go to voicemail with in-app playback |
| Push notifications | Alerts for incoming messages and calls, even when the app is backgrounded |
| Usage dashboard | Live tracking of texts sent and call minutes used against monthly caps |
| Rewarded unlocks | Watch an ad to earn bonus texts or call minutes when approaching the cap |
| Subscription tiers | Free (ad-supported), Ad-Free ($4.99/mo), Premium ($9.99/mo) with higher limits |
| Report and block | Per-conversation reporting and blocking for spam/abuse |
FreeLine is a three-tier system: native mobile clients, a backend API, and telephony providers.
iOS App (SwiftUI) ──┐
├──▶ Backend API (Fastify + TypeScript)
Android App (Compose)┘ │
├──▶ PostgreSQL (users, messages, calls, numbers)
├──▶ Redis (rate limits, caching, sessions)
├──▶ Bandwidth / Twilio (telephony)
├──▶ APNs / FCM (push notifications)
├──▶ RevenueCat (subscriptions)
└──▶ AdMob (ads)
All telecom operations sit behind a TelephonyProvider interface so the backend can swap providers without touching application logic.
- Bandwidth (primary): owns its own Tier 1 network, roughly 50% cheaper than Twilio at scale
- Twilio (fallback): more polished developer experience, used as contingency
- Stub (dev): deterministic responses for safe local testing
The provider handles number search/provisioning, SMS send/receive, voice token generation, and inbound call routing.
FreeLine uses VoIP, not the device's cellular radio. Inbound calls work even when the app is in the background:
- On iOS, PushKit delivers a silent wake notification and CallKit presents the native incoming call screen
- On Android, an FCM high-priority data message wakes the app and ConnectionService presents the native call UI
Outbound calls go through the Twilio Voice SDK with access tokens generated server-side.
User sends message ──▶ Backend validates (rate limits, policy, caps)
──▶ Bandwidth/Twilio sends SMS to PSTN
──▶ Webhook confirms delivery status
──▶ App updates with "Delivered" / "Read"
Recipient replies ──▶ Bandwidth/Twilio webhook hits backend
──▶ Backend stores message, resolves conversation
──▶ Push notification sent to user's device
──▶ Real-time WebSocket update to active app
Same basic formula as TextNow: free tier subsidized by ads, with paid upgrades for power users.
| Tier | Price | Texts/mo | Call Minutes/mo | Ads |
|---|---|---|---|---|
| Free | $0 | 40 (up to 80 with rewarded ads) | 15 (up to 35 with rewarded ads) | Banner, interstitial, rewarded |
| Ad-Free | $4.99/mo | 40 | 15 | None |
| Premium | $9.99/mo | 250 | 90 | None |
Ads show up in the inbox as banners, between calls as interstitials, and as opt-in rewarded videos to earn bonus usage. They never interrupt active conversations or calls.
Unit economics will kill a free telephony product if you don't control them. FreeLine enforces:
- Usage caps: daily and monthly limits on texts and call minutes per user
- Rate limiting: per-user and global rate limits on outbound traffic
- Inactivity reclaim: free numbers get recycled after 14 days of inactivity (warnings at day 10 and 13)
- Number quarantine: released numbers sit for 45 days before reassignment
- Trust scoring: new accounts start with conservative limits that relax over time
- First-7-day caps: 10 outbound texts/day, 5 unique contacts/day, 10 call minutes/day
- A2P 10DLC compliance: registered as application-to-person messaging for carrier compliance
User claims number ──▶ 24h activation window (must send/receive a real message or call)
──▶ Active: number stays assigned while account is used
──▶ Inactive 10 days: warning notification
──▶ Inactive 13 days: final warning
──▶ Inactive 14 days: number reclaimed
──▶ Quarantine (45 days): number cannot be reassigned
──▶ Available: number re-enters inventory
| Layer | Technology |
|---|---|
| iOS | SwiftUI, PushKit, CallKit, Twilio Voice SDK, AdMob SDK, RevenueCat |
| Android | Kotlin, Jetpack Compose, ConnectionService, FCM, Twilio Voice SDK, AdMob SDK, RevenueCat |
| Backend | TypeScript, Fastify, Node.js 18+ |
| Database | PostgreSQL |
| Cache | Redis |
| Telephony | Bandwidth (primary), Twilio (fallback) |
| Subscriptions | RevenueCat |
| Ads | Google AdMob |
| Auth | JWT, OAuth 2.0 (Apple, Google) |
FreeLine/
FreeLine-iOS/ SwiftUI iOS app
FreeLine-Android/ Kotlin + Jetpack Compose Android app
FreeLine-Backend/ TypeScript API server
phases/ Feature phase specs and verification artifacts
docs/ Privacy policy, terms of service, support
scripts/ Verification and automation
FreeLine now has a root Makefile so the repo can be driven from one top-level CLI instead of memorizing scattered shell commands.
make help
make doctor
make status
make install
make verify| Command | What it does |
|---|---|
make help |
Show the full CLI surface |
make doctor |
Check required and optional tooling for the repo |
make status |
Show branch, worktree counts, current phase, next target, and blocker summary |
make install |
Install backend and admin dependencies |
make install-hooks |
Install the repo pre-commit hook |
make backend-dev |
Run the backend API in watch mode |
make admin-dev |
Run the admin app in development mode |
| Command | What it does |
|---|---|
make run-ios-sim |
Build, install, and launch FreeLine on the first available iPhone simulator |
make run-ios-device |
Build, install, and launch on the first connected iPhone using ios-deploy |
make fix-ios-device |
Reset common macOS device bridge services when deploys hang |
make run-android-emulator |
Boot the first AVD if needed, then install and launch the Android app |
make run-android-device |
Install and launch on the first connected Android device |
| Command | What it does |
|---|---|
make verify |
Run the canonical repo build, lint, typecheck, and test gate |
make verify-native |
Run both native verification commands |
make verify-ios |
Build the iOS app for the first available simulator |
make verify-android |
Run Android unit tests, lint, and a debug build |
make verify-full |
Run repo verification plus both native platform checks |
make verify-ios-ui |
Placeholder for a future iOS UI test target |
make verify-phase PHASE=5-ads |
Run phases/<phase>/verify.sh directly |
make run-phase PHASE=5-ads |
Use the canonical phase helper from scripts/run_phase.sh |
| Command | What it does |
|---|---|
make current-phase |
Print the current phase from PROGRESS.md |
make next-phase |
Print the current unresolved target phase |
make proof-ios PHASE=5-ads |
Dispatch to the matching iOS proof-capture script |
make proof-android PHASE=2a-outbound-sms |
Dispatch to the matching Android proof-capture script |
If PHASE is omitted for proof-ios or proof-android, the CLI resolves the current unresolved phase from PROGRESS.md and uses it when a proof script is registered.
make doctorgives you a repo-specific environment audit instead of a generic "command not found" failure.make statusturnsPROGRESS.mdinto an actual operator dashboard by surfacing the current blocker and next target directly in the terminal.make proof-iosandmake proof-androidprovide a single proof-capture entrypoint that routes to the right phase script for supported phases.CLI_TODO.mdkeeps the remaining Igor-style CLI hookups explicit so the command surface can grow without pretending unfinished automation is done.
Advanced targets modeled after Igor's broader CLI surface are tracked in CLI_TODO.md. The current placeholders include verify-ios-ui, maestro-ios, maestro-android, playwright-*, device-tests*, phoneclaw-visual, distribute, forge-maintenance, and self-heal.
Auth: POST /v1/auth/email/start, /verify, /oauth/apple, /oauth/google, /refresh
Numbers: GET /v1/numbers/search?areaCode=..., POST /claim, GET /me, POST /release
Messaging: GET /v1/conversations, GET /:id/messages, POST /v1/messages
Calls: POST /v1/calls/token, GET /history, GET /voicemails
Controls: POST /v1/blocks, POST /v1/reports
Webhooks: POST /v1/webhooks/telecom/messages/inbound, /status, /calls/inbound, /status
FreeLine is a subsidized communications product, not a carrier plan. Every architectural decision comes back to per-user unit economics.
| Metric | Target |
|---|---|
| Telecom cost per active user | < $1.50/mo (Bandwidth) |
| Ad ARPU per active user | > $1.00/mo |
| Freemium conversion rate | > 3% |
| Idle number percentage | < 10% of provisioned |
At 10,000 active users, the app is projected to generate $3,000 - $8,000/month in gross margin.
Building FreeLine forced me to internalize the business mechanics behind a free telephony product. These are the things I learned by actually implementing them.
Every claimed number has a monthly cost whether the user touches it or not. On Bandwidth, a single number is $0.50/month just to hold. Add 40 texts and 15 call minutes and you're at ~$0.74/user/month. A maxed-out free user hitting the hard cap costs ~$1.21/month. The entire product is designed around this constraint.
| User Type | Monthly Telecom Cost |
|---|---|
| Claimed but churned within 14 days | $0.15 - $0.25 |
| Free user at included allowance (40 texts, 15 min) | ~$0.74 |
| Maxed free user at hard ceiling (80 texts, 35 min) | ~$1.21 |
| Paid subscriber (250 texts, 120 min) | ~$3.23 |
U.S. messaging app ad ARPU runs $0.50 - $2.00/month. That barely covers even a light free user. The business only works when you stack multiple revenue levers together:
- Aggressive free-tier caps keep per-user telecom cost bounded
- Banner + interstitial + rewarded ads generate baseline ARPU
- Freemium conversion at 3%+ produces $4.99 - $9.99/month subscribers who subsidize ~3-4 free users each
- Rewarded video is the highest-value ad format ($15-$30 eCPM) and also the mechanism that lets free users earn more usage, so user engagement and revenue point the same direction
- Number recycling eliminates the $0.50/month carrying cost on idle inventory
This is why TextNow's model works at scale. It's not an app with ads. It's an economic machine where every feature either generates revenue or controls cost.
If inactive users keep numbers forever, inventory cost grows linearly with total signups regardless of engagement. At 100,000 total signups with 20% active, you'd be paying $40,000/month to hold 80,000 idle numbers. The 14-day inactivity reclaim policy isn't punitive. It's what makes the free tier mathematically possible.
The 45-day quarantine after release prevents the wrong person from receiving someone else's messages. The 24-hour activation window prevents number hoarding. These aren't edge-case policies. They're load-bearing business logic.
A single spam account that sends 1,000 messages costs $4-$8 in telecom fees and can get the entire sending number pool flagged by carriers. Abuse controls (rate limits, trust scoring, first-7-day caps, unique contact limits) aren't a safety feature you bolt on later. They're a direct cost containment mechanism. One uncontrolled weekend of spam can burn through more telecom budget than a month of legitimate users.
Bandwidth owns its own Tier 1 network. Twilio resells capacity. The difference is roughly 50% on per-user cost:
| Bandwidth | Twilio | |
|---|---|---|
| Phone number | $0.50/mo | $1.15/mo |
| SMS per message | $0.004 | $0.0079 |
| Voice per minute | $0.010 | $0.014 |
| Light user total | ~$1.50/mo | ~$2.66/mo |
On Twilio, ad revenue alone cannot cover the cost of a free user. On Bandwidth, the gap is narrow enough that ads plus a small paid conversion rate can close it. Provider selection isn't a technical decision. It's the difference between a viable business and a cash incinerator.
Any app sending SMS from a U.S. 10-digit long code must register for A2P 10DLC. Campaign vetting takes 2-4 weeks. If you don't start registration on day one of development, your SMS feature is blocked at launch regardless of how polished the app is. This is one of those things that looks like a compliance checkbox but is actually a critical-path scheduling dependency.
- Ad-Free ($4.99/mo) removes ads but keeps the same usage limits. Margin: ~$4.25/mo. Straightforward profit from users who value the clean experience.
- Premium ($9.99/mo) adds higher caps (250 texts, 90 min) and a locked number. Margin: ~$6.77/mo. These users subsidize 5-9 free users each.
- Lock My Number ($1.99/mo) just disables the inactivity reclaim. Almost pure margin since it's a policy toggle, not a resource increase.
Every tier is priced to clear the telecom cost floor with room for infrastructure overhead. The free tier is really a user acquisition channel where ad revenue partially offsets the subsidy.
| Active Users | Monthly Telecom (included bundle) | Monthly Telecom (all maxed) | Projected Gross Margin |
|---|---|---|---|
| 100 | ~$74 | ~$121 | Pre-revenue |
| 1,000 | ~$740 | ~$1,210 | Approaching breakeven |
| 5,000 | ~$3,700 | ~$6,050 | $1,000 - $4,000/mo |
| 10,000 | ~$7,400 | ~$12,100 | $3,000 - $8,000/mo |
The model doesn't require venture funding to validate. Total cash burn to reach 1,000 active users is estimated at $500 - $1,500 over ~6 months. It flips to consistent profitability once ad fill rates stabilize, freemium conversion holds at 3%+, and number recycling keeps idle inventory below 10%.
Free phone numbers attract spam. It's the single biggest threat to user retention and the hardest problem to solve without destroying the user experience. FreeLine includes a real-time spam analysis system that scores every inbound message before it reaches the inbox.
When an SMS arrives, the backend runs it through a SpamAnalysisService that evaluates the message body against:
- Known scam patterns (gift card language, crypto solicitation, prize/lottery, wire transfer)
- Urgency pressure tactics ("act now", "immediately", "last chance")
- Brand and institution impersonation ("Apple Security", "your bank", "IRS")
- Shortened URLs from unknown senders (bit.ly, tinyurl from first-time contacts)
- ALL CAPS formatting (a mild signal that compounds with other flags)
Each message gets a confidence score (0.0 to 0.99) and a one-line reason. Messages scoring above 0.6 are flagged in the inbox with a coral "AI Spam Shield" badge showing the reason. The message text itself gets tinted to visually separate it from real conversations.
I picked spam defense over flashier AI features (chatbots, summaries, smart replies) because it's the one that actually matters for the business. A free phone number that gets flooded with spam is worthless. TextNow deals with this at scale, and I wanted to show that I understand the problem well enough to build a working solution.
The spam classifier runs server-side at message ingestion time, so there's no model download on mobile and no latency in the inbox. It enriches the existing message payload with spamConfidence and spamReason fields, so both iOS and Android display the warnings without any separate API call.
It also feeds directly into the existing abuse service. Patterns flagged by the AI classifier can inform trust scores, and when users tap "Report Spam" on a flagged message, the feedback loop tightens the filter for everyone.
This isn't a demo. The classifier, the backend enrichment, and the native UI badges are all wired end to end across all three layers of the stack.
I built FreeLine to prove to myself that I understand the TextNow product from the inside out. Not just the screens and the features, but the economics, the infrastructure, and the operational problems that make a free telephony product either work or bleed money.
This project covers:
- Telephony provider integration: Bandwidth as primary, Twilio as fallback, behind a swappable
TelephonyProviderinterface - Unit economics modeling: per-user cost tracking, usage caps, and the math behind subsidizing free numbers with ads and paid upgrades
- Abuse and cost controls: rate limiting, trust scoring, number recycling, and quarantine policies built into the foundation
- Native mobile development: separate SwiftUI (iOS) and Jetpack Compose (Android) codebases with platform-native call handling (PushKit/CallKit, FCM/ConnectionService)
- Monetization architecture: AdMob integration, RevenueCat subscriptions, and rewarded ad unlocks as the bridge between free and paid tiers
The full product (auth, number claiming, SMS, voice, voicemail, ads, subscriptions, abuse controls, admin ops, and number lifecycle management) is implemented across 11 execution phases, each with automated verification and proof artifacts for both platforms.













