safechat
v1.1.0
Published
Crisis safety for AI apps. Detects distress, finds local help. Zero location permissions.
Maintainers
Readme
What is SafeChat?
SafeChat is an international register and toolkit for chat safety protocol. Free for everyone. Built for developers, health professionals, and communities.
- Crisis Detection — Regex-based detection runs locally. No API calls. No data leaves the device. Catches misspellings, text-speak, indirect warning signs, and passive suicidality.
- Geo-Location (No GPS) — Finds the user's country from timezone and locale. No permissions needed. 7-layer cascade.
- Verified Helpline Database — 100+ helplines across 34 countries. Phone, text, chat, email, WhatsApp. CC0 public domain.
- AI Prompt Override — System prompt injections that tell your LLM to show crisis resources. Works with any AI provider.
- Drop-in UI — Modal, banner, and full-page popup. One script tag. PWA-capable. Works offline.
- Compliance-Ready — Aligned with NY AI Companion Law, FTC chatbot safety requirements, VERA-MH framework, and Samaritans guidelines.
Install as App (PWA)
SafeChat works as a standalone app on any device:
- iPhone/iPad: Open the popup in Safari → tap Share → "Add to Home Screen"
- Android: Open in Chrome → menu → "Install App"
- Desktop: Open in Chrome/Edge → click install icon in address bar
Open the popup: rob-e-graham.github.io/safechat/app/popup.html
Quick Start
Browser (no build step)
<script src="https://cdn.jsdelivr.net/gh/rob-e-graham/safechat@main/src/browser.js"></script>
<script>
Safechat.protect(); // auto-monitor all text inputs
</script>One-line embed
<script src="https://cdn.jsdelivr.net/gh/rob-e-graham/safechat@main/src/embed.js"
data-safechat-monitor="true"></script>Node.js / npm
npm install safechatconst safechat = require('safechat');
const safety = safechat.check(userMessage);
if (safety.level === 'high') {
systemPrompt = safechat.promptOverride('high', safety.country)
+ '\n\n' + systemPrompt;
}Express middleware
const safechat = require('safechat');
app.use(safechat.middleware());
app.post('/api/chat', (req, res) => {
const safety = req.safechat.check(req.body.message);
if (safety.action === 'crisis_intervention') {
systemPrompt = req.safechat.promptOverride(safety.level) + '\n\n' + systemPrompt;
}
});Embed the popup
<iframe src="https://rob-e-graham.github.io/safechat/app/popup.html"
style="width:100%;max-width:480px;height:700px;border:none;border-radius:16px;">
</iframe>How Detection Works
Detection uses regex pattern matching with three layers:
- Input normalisation — Smart quotes → ASCII, whitespace collapse, misspelling correction, text-speak expansion
- Pattern matching — HIGH signals (explicit suicidal language, methods) and LOW signals (hopelessness, worthlessness)
- False-positive guards — Context-aware filtering skips figurative language ("cut my hair", "suicide squeeze play", "overdosed on coffee")
| Level | Triggers | Action | |-------|----------|--------| | high | Suicidal ideation, self-harm, explicit intent | Show crisis resources immediately | | low | Hopelessness, worthlessness, feeling trapped | Soft safety response with helpline link | | none | No crisis signals | Normal operation |
Geo-Detection
SafeChat finds the user's country without location permissions:
| Priority | Method | Permissions |
|----------|--------|-------------|
| 1 | Browser locale (navigator.language) | None |
| 2 | Timezone (Intl.DateTimeFormat) | None |
| 3 | CDN headers (CF-IPCountry, X-Vercel-IP-Country) | None |
| 4 | Accept-Language header | None |
| 5 | Manual override | None |
| 6 | Global fallback (findahelpline.com) | None |
Auto-Updating Crisis Data
1. jsDelivr CDN (latest data) ← primary
2. GitHub raw (same data, different CDN) ← if jsDelivr down
3. localStorage cache ← if offline
4. Inline emergency numbers ← if never loadedVerification workflow runs twice monthly to check all phone numbers and URLs.
Security
SafeChat is designed for trust:
- Zero data collection — all detection runs locally, nothing is transmitted
- Content Security Policy — CSP headers on all pages
- HTML escaping — all dynamic content is escaped to prevent XSS
- Input validation — type checking, ReDoS protection, JSON structure validation
- Scoped service worker — only intercepts same-origin requests
- No cookies, no analytics, no tracking
- 424 automated tests including security/adversarial inputs
- Referrer policy —
no-referreron all pages
API
safechat.check(text, options?)
safechat.check("I can't go on anymore", { country: "AU" });
// { level: "low", matched: "can't go on", country: "AU", action: "soft_warning", resources: {...} }safechat.detect(text)
safechat.detect("I want to kill myself") // { level: "high", matched: "kill myself" }
safechat.detect("I feel worthless") // { level: "low", matched: "worthless" }
safechat.detect("great day today") // { level: "none", matched: null }safechat.promptOverride(level, countryCode)
safechat.getResources(countryCode, options?)
safechat.middleware()
Countries Covered
Australia, Austria, Belgium, Brazil, Canada, China, Denmark, Finland, France, Germany, Ghana, Hong Kong, India, Ireland, Israel, Italy, Japan, Kenya, Mexico, Netherlands, New Zealand, Nigeria, Norway, Pakistan, Philippines, Portugal, Russia, South Africa, South Korea, Spain, Sweden, Switzerland, United Kingdom, United States.
Plus global fallback via findahelpline.com (175+ countries).
Ongoing Development
SafeChat is under continuous, active development. See CHANGELOG.md for a full record of detection improvements, new patterns, and accuracy gains. Every change is tested, timestamped, and publicly documented.
- False negatives are treated as critical defects
- Crisis resource data is verified twice monthly
- Test suite must pass before every release (currently 424 tests)
- Detection patterns are reviewed against published clinical literature
Licensing
SafeChat uses Business Source License (BSL 1.1).
Free for:
- Personal, educational, research, nonprofit/community use
- Commercial entities under $100,000 USD annual revenue
Commercial entities over $100K must obtain a commercial license: [email protected]
Changes to MPL 2.0 on 2029-01-01.
Legal Disclaimer
SafeChat is provided as is. It is not emergency medical care, legal advice, professional mental health treatment, or a substitute for emergency services, clinicians, safeguarding teams, or local crisis procedures.
By downloading, installing, deploying, integrating, or using SafeChat, you accept responsibility for your own installation, configuration, compliance, testing, supervision, and use. To the maximum extent permitted by law, Rob Graham, FAMTEC, contributors, maintainers, copyright holders, and licensors are not liable for damages, losses, legal claims, regulatory penalties, system damage, data loss, personal injury, death, failure to obtain help, failure to detect crisis content, unlawful use, or other harm arising from installation or use.
SafeChat is a routing layer, not a diagnostic tool. It identifies textual signals and connects users to professional resources. It does not assess clinical risk or replace professional mental health services.
If you do not accept these terms, do not download, install, deploy, integrate, or use SafeChat. See LICENSE and docs/legal-disclaimer.md for the full disclaimer, integrator responsibilities, and limitation of liability.
Support the Project
Contributing
Help keep crisis resources accurate and expand to more countries. See CONTRIBUTING.md.
This project follows Samaritans safe messaging guidelines.
Community
- GitHub Discussions — questions, research, standards
- Issues — bugs, wrong numbers, detection gaps
- FAMTEC — the team behind SafeChat
