What this page is. Every safety feature in Safe2Go: what happens and when, what's sent to whom, and what is and isn't live yet. Written from the code in server/services/safetyEngine.js, server/routes/safety.js and the Safety Mode screens in public/index.html. Last updated 2026-09-26 (commits ad335ab, 2892a10).
Status labels:LIVE working now ยท
NEEDS SETUP built, waiting on an account/config ยท
NOT YET not built
1. The whole flow
flowchart TD
A["User sets up Safety Profile: up to 5 emergency contacts + 4-digit safety code"] --> B["Starts a journey and turns on SAFETY MODE"]
B --> C["Server opens a safety session (route, legs, live-location link, local police number)"]
C --> D{"Off the planned route? more than 500 m for 60 s (phone screen OR background GPS)"}
D -- no --> D
D -- yes --> P1["ARE YOU SAFE? โ check 1 of 3 30 seconds"]
P1 --> Q1{"Code entered?"}
Q1 -- "correct code" --> SAFE["You're Safe โ back to monitoring"]
Q1 -- "reverse (duress) code" --> DUR["Screen shows 'You're Safe' โ BUT everyone is alerted immediately"]
Q1 -- "no code in 30 s" --> P2["Check 2 of 3 โ 30 seconds"]
P2 --> Q2{"Code entered?"}
Q2 -- correct --> SAFE
Q2 -- duress --> DUR
Q2 -- "no code in 30 s" --> P3["Check 3 of 3 โ FINAL โ 30 seconds"]
P3 --> Q3{"Code entered?"}
Q3 -- correct --> SAFE
Q3 -- duress --> DUR
Q3 -- "no code in 30 s" --> ESC["๐ ESCALATE (after 90 s)"]
DUR --> ESCD["๐ ESCALATE silently"]
ESC --> OUT["Every contact: email + SMS + automated phone call with last location, live-tracking link, and 'call the police (local number)'"]
ESCD --> OUT
ESC --> SCR["User's screen: EMERGENCY ALERT SENT ๐ Call police button + ๐ your location"]
SCR --> AC{"User enters correct code later?"}
AC -- yes --> ALL["All contacts told: 'they have confirmed they are safe'"]
The timer runs on the server, not on the phone. The checks and the escalation still happen if the phone is locked, the app is closed, the battery dies or the phone is taken away.
2. Feature list
#
Feature
How it works
Status
1
Safety Profile
Home, office and 2 safe places, up to 5 emergency contacts (name + phone with country code and/or email), and a 4-digit safety code. Palindrome codes (e.g. 1221) are refused, because their reverse would be the same code.
LIVE
2
Safety Mode (opt-in)
Turned on by the user during a journey. Needs a profile with at least one contact. Turning it off, or finishing the journey, closes the session.
LIVE
3
Off-route detection
More than 500 m from the planned route for 60 s. Checked on the phone screen, and on the server from the app's background GPS reports (every 30 s). Flight legs are ignored.
LIVE
4
"Are you safe?" โ 3 checks ร 30 s
Check 1 โ 30 s โ check 2 โ 30 s โ check 3 (FINAL) โ 30 s โ escalation. Each check shows its number and a countdown, with a beep and vibration (Android). Repeated off-route signals never restart or delay a running cycle.
LIVE
5
Correct code
"You're Safe!" and back to monitoring. After an escalation, all contacts get an all-clear message.
LIVE
6
Wrong code
"Wrong safety code. Try again." It does not pause the 30-second windows.
LIVE
7
Duress (reverse) code
E.g. 1234 โ 4321. See section 3.
LIVE
8
Server-side timer
Runs every 5 s on the server, so escalation never depends on the phone being on or in hand.
LIVE
9
Escalation to all contacts
Email + SMS + automated voice call to every contact. See section 4.
Email LIVESMS/calls NEED TWILIO
10
Police numbers by location
Local police number (and general emergency number where different), from the user's latest location. See section 5.
LIVE
11
Location in every alert
Address + GPS + how long ago + Google Maps link + live-tracking link. See section 6.
LIVE
12
"Alert Emergency Contacts Now"
Manual button on the alert screen, which escalates immediately.
LIVE
13
๐ Call police button
Always on the alert screen, one tap to the local police number. It shows a second button for ambulance/fire when that number differs.
LIVE
14
"Your location (tell the police)" box
The alert screen shows the user's current address and GPS so they can read it to the operator.
LIVE
15
Text/Call contact buttons
Shown on the emergency screen only while SMS/calls aren't set up, so the user can reach phone contacts by hand.
LIVE
16
Event log
Every escalation and all-clear is recorded (safety_events): reason, location, and delivery result per contact and channel.
LIVE
3. Duress code
flowchart LR
A["Someone forces the user to say they're safe"] --> B["User enters the code REVERSED, e.g. 4321"]
B --> C["Screen: 'You're Safe!' โ identical to the real code"]
B --> D["Session looks normal (nothing visible changes)"]
B --> E["Server immediately alerts ALL contacts: email + SMS + call 'URGENT โ may be in danger, forced to appear safe' + location + call the police"]
Nothing on the screen gives it away. The person watching sees exactly what the real code shows.
4. Escalation โ who gets what
Trigger
Message opening
No answer to 3 checks
"SAFETY ALERT: name went off their planned route on Safe2Go and did not confirm they are safe after 3 checks."
Duress code
"URGENT: name entered their DURESS code on Safe2Go. They may be in danger and forced to appear safe."
Manual button
"SAFETY ALERT: name pressed the emergency button on Safe2Go."
Correct code after an alert
"UPDATE: name has now confirmed with their safety code that they are safe." (email + SMS, no call)
Channel
Sent to
Contains
Status
๐ง Email
Every contact with an email
Alert, action ("call them now; if you can't reach them, call the police โฆ"), time, route, last address + GPS + how long ago, Google Maps button, live-location button
LIVE (via the server's Gmail account)
๐ฌ SMS
Every contact with a phone number
Same content as one text, with the Maps and live-tracking links
NEEDS TWILIO
๐ Automated voice call
Every contact with a phone number
Alert read out twice, including the address and the GPS coordinates read digit by digit, plus the police number
NEEDS TWILIO
๐ Police
โ
Automated calls to 112/911/100 are not permitted in most countries. Instead: every contact is told to call the police with the location, the user has a one-tap police button, and the location is shown on screen to read out.
LIVE
5. Police numbers โ from the user's latest location
flowchart TD
G["User's latest GPS position"] --> C{"Country lookup (mobility_graph DB)"}
C --> B["Country boundary polygons (authoritative where available)"]
C --> P["Nearest place within 15 km (covers small countries: SG, MT, MC, BH, HKโฆ)"]
B --> ISO["Country code, e.g. DE"]
P --> ISO
ISO --> T["Police table โ police 110 / emergency 112"]
T --> W["Refreshed when moved more than 10 km or every 10 min, and looked up FRESH at the moment of any alert"]
C -- "no country (e.g. at sea)" --> F["Fallback 112 (works from any mobile phone in most countries)"]
Examples (verified 2026-09-26):
Location
Country
Police
General emergency
Mannheim
DE
110
112
Basel
CH
117
112
Strasbourg
FR
17
112
Salzburg
AT
133
112
Delhi
IN
112
112
Kathmandu
NP
100
100
Singapore
SG
999
999
Dubai
AE
999
999
London
GB
999
999
New York
US
911
911
Sydney
AU
000
000
Sรฃo Paulo
BR
190
190
Mid-Atlantic
โ
112
112
Moving-user test: journey started in Mannheim (110) โ phone update from Basel (117) โ background update from Strasbourg (17) โ alert sent from Salzburg used 133.
Border limitation: within a few km of a border, the low-resolution boundary data can pick the neighbouring country (seen: Weil am Rhein, Germany, read as Switzerland). Both numbers are shown where they differ, and 112 is always a working fallback on mobile phones.
6. Location sharing
Where
What location is shared
SMS
"Last location (N min ago): address โ GPS lat, lng" + Google Maps link + live-tracking link
Email
Address, GPS, how long ago, Google Maps button, "Follow live location" button
Voice call
Address read out, GPS read digit by digit (e.g. "4 9 point 4 8 7 3 3"), and a note that the links were sent by text and email
Live tracking
/live-track.html?token=โฆ, a private link per session, kept current from every GPS update
User's own screen
"๐ Your location (tell the police)": address + GPS, refreshed as they move
"Last location" is the latest GPS position the server received: from the phone screen, or from the app's background reports every 30 s.
7. Phone apps (Android / iOS)
The store apps are a wrapper around the live website (mobile_native/index.js โ AppWebView). Everything on the safety screens is therefore the same in both apps, with no store update needed.
Item
Android
iOS
All safety screens (checks, countdown, police button, location box, contacts)
LIVE
LIVE
๐ / ๐ฌ buttons open the dialer / SMS app
LIVE
LIVE
Background GPS reports โ server off-route check + escalation
LIVE
not yet confirmed on a real iPhone
Vibration on each check
should work
not possible from the web page
"Are you safe?" pop-up while the app is closed / phone locked
NOT YET
NOT YET
No lock-screen pop-up yet: the apps have no notifications, so a user with the app in the background sees the check only when they open it. The server still escalates after 90 s. Fixing this needs a native update (local/push notification with an alarm sound) and a store release on both platforms.
8. Setup & open items
#
Item
What's needed
1
SMS + automated calls
A Twilio account and one phone number. In Railway set TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN, TWILIO_FROM_NUMBER. No code change needed; it switches on automatically.
2
Confirm email alerts in production
One real test: a profile with your own email, Safety Mode on, press "Alert Emergency Contacts Now".
3
Lock-screen pop-up
Native notification in the Android/iOS wrapper + store releases.
4
Road-accurate off-route check
Today off-route is measured against straight lines between stops, so winding roads can cause false prompts. Needs road shapes on routes (part of the TO-BE plan).
5
Real-device test
Safety flow on a physical Android phone and iPhone.
9. How it was tested (2026-09-26)
End-to-end, real timers (24/24 passed, run 3 times): profile validation, session start, check 1 โ 2 โ 3 at 30 s each, escalation at 90 s, correct code, wrong code, duress (looks safe, escalates), background-GPS off-route starting a check, manual alert, all-clear after escalation, session stop.